使用 Reporting API 监控安全违规行为、已弃用的 API 调用等。
有些错误只发生在生产环境中。您不会在本地或开发期间看到它们,因为真实用户、真实网络和真实设备会改变游戏规则。Reporting API 有助于捕获其中一些错误(例如整个网站中的安全违规或已弃用和即将弃用的 API 调用),并将其传输到您指定的端点。
它允许您通过 HTTP 标头声明要监控的内容,并且由浏览器操作。
设置 Reporting API 后,您就会知道,当用户遇到这些类型的错误时,可以进行修复,这让您高枕无忧。
这篇博文将介绍此 API 的功能和用法。那就进入正题吧!
演示和代码
查看 Reporting API 从 Chrome 96 及更高版本(自 2021 年 10 月起适用于 Chrome Beta 版或 Canary 版)的实际应用。
概览
假设您的网站 site.example
既有内容安全政策,也有文档政策。不知道这些按钮的用途?没关系,您仍然能够理解此示例。
您决定监控您的网站,以便了解何时违反了这些政策,同时,也因为您希望密切关注您的代码库正在使用的已废弃或即将弃用的 API。
为此,请配置 Reporting-Endpoints
标头,并根据需要通过政策中的 report-to
指令映射这些端点名称。
Reporting-Endpoints: main-endpoint="https://reports.example/main", default="https://reports.example/default"
# Content-Security-Policy violations and Document-Policy violations
# will be sent to main-endpoint
Content-Security-Policy: script-src 'self'; object-src 'none'; report-to main-endpoint;
Document-Policy: document-write=?0; report-to=main-endpoint;
# Deprecation reports don't need an explicit endpoint because
# these reports are always sent to the `default` endpoint
出现意外情况,您的部分用户违反了这些政策。
违规行为示例
index.html
<script src="script.js"></script>
<!-- CSP VIOLATION: Try to load a script that's forbidden as per the Content-Security-Policy -->
<script src="https://example.com/script.js"></script>
script.js
,由 index.html
加载
// DOCUMENT-POLICY VIOLATION: Attempt to use document.write despite the document policy
try {
document.write('<h1>hi</h1>');
} catch (e) {
console.log(e);
}
// DEPRECATION: Call a deprecated API
const webkitStorageInfo = window.webkitStorageInfo;
浏览器会生成一份捕获这些问题的 CSP 违规报告、“文档政策违规”报告和“弃用”报告。
浏览器会在短暂的延迟(长达一分钟)后将报告发送到为此违规类型配置的端点。报告由浏览器本身带外发送(而不是由您的服务器或您的网站发送)。
端点接收这些报告。
您现在可以访问这些端点上的报告并监控出了什么问题。您可以开始排查影响用户的问题了。
示例报告
{
"age": 2,
"body": {
"blockedURL": "https://site2.example/script.js",
"disposition": "enforce",
"documentURL": "https://site.example",
"effectiveDirective": "script-src-elem",
"originalPolicy": "script-src 'self'; object-src 'none'; report-to main-endpoint;",
"referrer": "https://site.example",
"sample": "",
"statusCode": 200
},
"type": "csp-violation",
"url": "https://site.example",
"user_agent": "Mozilla/5.0... Chrome/92.0.4504.0"
}
使用情形和报告类型
您可以配置 Reporting API 来帮助您监控网站中发生的多种值得注意的警告或问题:
报告类型 | 生成报告的情况示例 |
---|---|
CSP 违规(仅限 3 级) | 您在自己的一个网页上设置了 Content-Security-Policy (CSP),但该网页正尝试加载 CSP 不允许的脚本。 |
违反了 COOP | 您已在网页上设置了 Cross-Origin-Opener-Policy ,但跨源窗口正尝试与文档直接交互。 |
违反了 COEP | 您已在网页上设置了 Cross-Origin-Embedder-Policy ,但文档包含未选择由跨源文档加载的跨源 iframe。 |
违反文档政策 | 该网页的一项文档政策禁止使用 document.write ,但有脚本试图调用 document.write 。 |
违反权限政策 | 该页面设置了禁止使用麦克风的权限政策,以及请求音频输入的脚本。 |
弃用警告 | 网页使用的 API 已弃用或即将被弃用;它直接调用或通过顶级第三方脚本调用。 |
干预 | 出于安全性、性能或用户体验方面的原因,该网页正试图执行浏览器决定不遵从的操作。Chrome 中的示例:在网速较慢时,网页使用 document.write ,或者在用户尚未与之交互的跨源帧中调用 navigator.vibrate 。 |
交通事故 | 打开您的网站时,浏览器发生崩溃。 |
报告
报告是什么样的?
浏览器会将报告发送到您配置的端点。它将发送如下请求:
POST
Content-Type: application/reports+json
这些请求的载荷是报告列表。
报告列表示例
[
{
"age": 420,
"body": {
"columnNumber": 12,
"disposition": "enforce",
"lineNumber": 11,
"message": "Document policy violation: document-write is not allowed in this document.",
"policyId": "document-write",
"sourceFile": "https://site.example/script.js"
},
"type": "document-policy-violation",
"url": "https://site.example/",
"user_agent": "Mozilla/5.0... Chrome/92.0.4504.0"
},
{
"age": 510,
"body": {
"blockedURL": "https://site.example/img.jpg",
"destination": "image",
"disposition": "enforce",
"type": "corp"
},
"type": "coep",
"url": "https://dummy.example/",
"user_agent": "Mozilla/5.0... Chrome/92.0.4504.0"
}
]
以下是您可以在每份报告中找到的数据:
字段 | 说明 |
---|---|
age |
报告的时间戳与当前时间之间的毫秒数。 |
body |
实际报告数据,已序列化为 JSON 字符串。报告的 body 中包含的字段由报告的 type 确定。⚠️ 不同类型的报告有不同的正文。
若要查看每种报告的确切正文,请查看演示报告端点 ,并按照说明生成示例报告。 |
type |
报告类型,例如 csp-violation 或 coep 。 |
url |
生成报告时所用的文档或工作器的地址。用户名、密码和片段等敏感数据会从此网址中删除。 |
user_agent |
生成报告的请求的 User-Agent 标头。 |
已凭证的报告
与生成报告的网页具有相同来源的报告端点会在包含报告的请求中接收凭据 (Cookie)。
凭据可以提供有关报告的其他有用背景信息;例如,指定用户的账号是否持续触发错误,或者在其他页面上执行的某种操作是否触发了此页面上的报告。
浏览器何时以及如何发送报告?
从您的网站以带外方式传送报告:浏览器控制何时将报告发送到配置的端点。此外,浏览器也无法控制何时发送报告;它会捕获报告、将报告加入队列并在适当的时间自动发送报告。
这意味着在使用 Reporting API 时,几乎没有什么性能问题。
报告会延迟发送(最长可达一分钟),以提高批量发送报告的几率。 这样可以节省带宽,以尊重用户的网络连接,这对于移动设备尤为重要。此外,如果浏览器忙于处理优先级较高的工作,或者用户当前所用网络速度较慢和/或网络拥塞,则也可能会延迟传送内容。
第三方和第一方问题
由于您的网页上出现违规行为或弃用而生成的报告将发送到您配置的端点。其中包括由网页上运行的第三方脚本造成的违规行为。
嵌入您网页中的跨源 iframe 中发生的违规或弃用情况不会向您的端点报告(至少默认情况下不会报告)。iframe 可能会设置自己的报告,甚至向您网站的(即第一方)报告服务报告;但这取决于加框网站。另请注意,大多数报告仅在违反网页政策时才会生成,并且该网页的政策与 iframe 的政策不同。
弃用功能示例
浏览器支持
下表总结了浏览器对 Reporting API v1 的支持情况,即使用 Reporting-Endpoints
标头。浏览器对 Reporting API v0(Report-To
标头)的支持相同,但有一种报告类型除外:新的 Reporting API 不支持网络错误日志记录。如需了解详情,请参阅迁移指南。
报告类型 | Chrome | iOS 版 Chrome | Safari | Firefox | Edge |
---|---|---|---|---|---|
CSP 违规(仅限 3 级)* | ✔ 是 | ✔ 是 | ✔ 是 | ✘ 否 | ✔ 是 |
网络错误日志记录 | ✘ 否 | ✘ 否 | ✘ 否 | ✘ 否 | ✘ 否 |
违反 COOP/COEP | ✔ 是 | ✘ 否 | ✔ 是 | ✘ 否 | ✔ 是 |
所有其他类型:违反文档政策、弃用、干预、崩溃 | ✔ 是 | ✘ 否 | ✘ 否 | ✘ 否 | ✔ 是 |
下表仅总结了对带有新 Reporting-Endpoints
头文件的 report-to
的支持。如果您希望迁移到 Reporting-Endpoints
,请参阅 CSP 报告迁移提示。
使用 Reporting API
决定应将报告发送到何处
您可以采用以下两种方法:
- 将报告发送到现有的报告收集器服务。
- 将报告发送给自己构建和运营的报告收集器。
方法 1:使用现有报告收集器服务
下面列举了一些报告收集器服务:
如果您知道其他解决方案,请提交问题告诉我们,我们会更新这篇博文!
在选择报告收集器时,除了价格之外,还请考虑以下要点:🧐?
- 此收集器是否支持所有报告类型?例如,并非所有报告端点解决方案都支持 COOP/COEP 报告。
- 您是否愿意与第三方报告收集器共享您应用的任何网址? 即使浏览器从这些网址中删除了敏感信息,敏感信息也可能会以这种方式泄露。如果这对于您的应用来说风险过高,请运行您自己的报告端点。
选项 2:构建和运行您自己的报告收集器
构建您自己的接收报告的服务器并非易事。首先,你可以复制我们的轻量级样板。它是通过 Express 构建的,可以接收和显示报告。
前往样板报告收集器。
点击 Remix to Edit 使项目可修改。
现在,您有自己的克隆人了!您可以根据自己的需要对其进行自定义。
如果您未使用样板代码,而是从头开始构建自己的服务器:
- 检查
Content-Type
为application/reports+json
的POST
请求,以识别浏览器向端点发送的报告请求。 - 如果您的端点与您的网站位于不同的来源,请确保它支持 CORS 预检请求。
选项 3:将选项 1 和选项 2 结合使用
您可能希望特定提供商处理某些类型的报告,但为其他类型的报告提供内部解决方案。
在这种情况下,请按如下方式设置多个端点:
Reporting-Endpoints: endpoint-1="https://reports-collector.example", endpoint-2="https://my-custom-endpoint.example"
配置 Reporting-Endpoints
标头
设置 Reporting-Endpoints
响应标头。它的值必须是一个或一系列以英文逗号分隔的键值对:
Reporting-Endpoints: main-endpoint="https://reports.example/main", default="https://reports.example/default"
如果您要从旧版 Reporting API 迁移到新版 Reporting API,则可能需要同时设置 Reporting-Endpoints
和 Report-To
。如需了解详情,请参阅迁移指南。特别是,如果您仅通过 report-uri
指令来报告 Content-Security-Policy
违规,请参阅CSP 报告的迁移步骤。
Reporting-Endpoints: main-endpoint="https://reports.example/main", default="https://reports.example/default"
Report-To: ...
键(端点名称)
每个键可以是您选择的名称,例如 main-endpoint
或 endpoint-1
。您可以决定为不同的报告类型设置不同的命名端点,例如 my-coop-endpoint
和 my-csp-endpoint
。这样,您就可以根据类型将报告路由到不同的端点。
如果您想要接收干预、弃用和/或崩溃报告,请设置名为 default
的端点。
如果 Reporting-Endpoints
标头未定义 default
端点,系统将不会发送此类型的报告(不过会生成报告)。
值(网址)
每个值都是您选择的网址,报告将发送到该网址。此处设置的网址取决于您在第 1 步中确定的网址。
端点网址:
- 必须以斜杠 (
/
) 开头。不支持相对路径。 - 可以是跨源的;但在这种情况下,凭据不会随报告一起发送。
示例
Reporting-Endpoints: my-coop-endpoint="https://reports.example/coop", my-csp-endpoint="https://reports.example/csp", default="https://reports.example/default"
然后,您可以在适当的政策中使用每个已命名的端点,也可以针对所有政策使用一个端点。
在何处设置标题?
在新的 Reporting API(这篇博文介绍的 API)中,报告的范围限定为文档。这意味着,对于一个给定的源站,不同的文档(如 site.example/page1
和 site.example/page2
)可以将报告发送到不同的端点。
若要接收网站任何页面上发生的违规行为或弃用情况报告,请将所有响应的标头设置为中间件。
以下是 Express 中的示例:
const REPORTING_ENDPOINT_BASE = 'https://report.example';
const REPORTING_ENDPOINT_MAIN = `${REPORTING_ENDPOINT_BASE}/main`;
const REPORTING_ENDPOINT_DEFAULT = `${REPORTING_ENDPOINT_BASE}/default`;
app.use(function (request, response, next) {
// Set up the Reporting API
response.set(
'Reporting-Endpoints',
`main-endpoint="${REPORTING_ENDPOINT_MAIN}", default="${REPORTING_ENDPOINT_DEFAULT}"`,
);
next();
});
修改您的政策
现在,Reporting-Endpoints
标头已配置完毕,请为您希望接收违规报告的每个政策标头分别添加一个 report-to
指令。report-to
的值应该是您已配置的指定端点之一。
您可以将多个端点用于多项政策,也可以针对多项政策使用不同的端点。
弃用、干预和崩溃报告不需要 report-to
。这些报告不受任何政策的约束。只要设置了 default
端点并发送到此 default
端点,系统就会生成这些日志。
示例
# Content-Security-Policy violations and Document-Policy violations
# will be sent to main-endpoint
Content-Security-Policy: script-src 'self'; object-src 'none'; report-to main-endpoint;
Document-Policy: document-write=?0;report-to=main-endpoint;
# Deprecation reports don't need an explicit endpoint because
# these reports are always sent to the default endpoint
示例代码
为了在上下文中了解所有情况,下面是一个使用 Express 的 Node 服务器示例,该服务器汇总了本文中讨论的所有部分。该部分展示了如何为几种不同的报告类型配置报告,并显示了结果。
调试报告设置
有意识地生成报告
设置 Reporting API 时,您可能需要故意违反相关政策,以便检查报告是否按预期生成和发送。如需查看违反政策的示例代码以及会执行生成所有类型的报告的其他不良操作,请查看演示。
节省时间
报告可能会延迟发送(大约一分钟),在调试时,这需要很长时间。🎁? 幸运的是,在 Chrome 中进行调试时,您可以使用 --short-reporting-delay
标志在报告生成后立即收到报告。
在终端中运行以下命令以启用此标志:
YOUR_PATH/TO/EXECUTABLE/Chrome --short-reporting-delay
使用开发者工具
在 Chrome 中,使用开发者工具查看已发送或将要发送的报告。
截至 2021 年 10 月,此功能处于实验阶段。若要使用它,请按以下步骤操作:
- 使用 Chrome 96 及更高版本(在浏览器中输入
chrome://version
进行检查) - 在 Chrome 的网址栏中输入或粘贴“
chrome://flags/#enable-experimental-web-platform-features
”。 - 点击已启用。
- 重启浏览器。
- 打开 Chrome 开发者工具。
- 在 Chrome 开发者工具中,打开“设置”。在“实验”下,点击“应用”面板中的“启用 Reporting API”面板。
- 重新加载开发者工具。
- 重新加载页面。打开开发者工具页面生成的报告将列在 Chrome 开发者工具的 Application 面板中的 Reporting API 下。
报告状态
状态列会显示报告是否已成功发送。
状态 | 说明 |
---|---|
Success |
浏览器已发送报告,端点返回了成功代码(200 或其他成功响应代码 2xx )。 |
Pending |
浏览器正在尝试发送报告。 |
Queued |
报告已生成,浏览器目前并未尝试发送它。在以下两种情况下,报告会显示为 Queued :
|
MarkedForRemoval |
重试一段时间 (Queued ) 后,浏览器已停止尝试发送报告,很快便会从要发送的报告列表中移除。 |
一段时间后,系统会移除相关报告,无论这些报告是否成功发送。
问题排查
是否未生成报告或未按预期将报告发送到您的端点?以下是一些有助于排查此问题的提示。
未生成报告
开发者工具中显示的报告已正确生成。 如果您需要的报告没有显示在此列表中,请执行以下操作:
- 请在您的政策中查看
report-to
。如果配置有误,将无法生成报告。如需解决此问题,请访问修改政策。排查此问题的另一种方法是查看 Chrome 中的开发者工具控制台:如果控制台中弹出您预期的违规错误,则表示您的政策可能配置正确。 - 请注意,只有为打开开发者工具的文档生成的报告才会显示在此列表中。例如:如果您的网站
site1.example
嵌入的 iframesite2.example
违反了政策,并因此生成报告,则只有当您在自己的窗口中打开 iframe 并为该窗口打开开发者工具时,此报告才会显示在开发者工具中。
已生成报告,但无法发送或未收到报告
如果您可以在开发者工具中看到报告,但端点没有收到,该怎么办?
- 请务必使用短暂延迟。您看不到报告的原因可能是由于报告尚未发送!
请检查您的
Reporting-Endpoints
标头配置。如果存在问题,系统不会发送正确生成的报告。在这种情况下,在开发者工具中,报告的状态将保持为Queued
(它可能会跳转到Pending
,然后在尝试传送时快速返回Queued
)。可能导致这种情况的一些常见错误包括:端点已被使用,但尚未配置。例如:
Document-Policy: document-write=?0;report-to=endpoint-1; Reporting-Endpoints: default="https://reports.example/default"
缺少
default
端点。某些报告类型(例如弃用报告和干预报告)仅会发送到名为default
的端点。如需了解详情,请参阅配置报告端点标头。查找政策标头语法中是否存在问题,例如缺少引号。查看详情。
检查您的端点是否可以处理传入请求。
确保您的端点支持 CORS 预检请求。否则将无法接收报告。
测试端点的行为。为此,您可以将浏览器发送的端点请求发送到端点请求来模拟浏览器,而无需手动生成报告。运行以下命令:
curl --header "Content-Type: application/reports+json" \ --request POST \ --data '[{"age":420,"body":{"columnNumber":12,"disposition":"enforce","lineNumber":11,"message":"Document policy violation: document-write is not allowed in this document.","policyId":"document-write","sourceFile":"https://dummy.example/script.js"},"type":"document-policy-violation","url":"https://dummy.example/","user_agent":"xxx"},{"age":510,"body":{"blockedURL":"https://dummy.example/img.jpg","destination":"image","disposition":"enforce","type":"corp"},"type":"coep","url":"https://dummy.example/","user_agent":"xxx"}]' \ YOUR_ENDPOINT
您的端点应该使用成功代码(
200
或其他成功响应代码2xx
)进行响应。如果没有,则表示其配置存在问题。
相关举报机制
仅用于报告
-Report-Only
政策标头和 Reporting-Endpoints
可搭配使用。
在 Reporting-Endpoints
中配置并在 Content-Security-Policy
、Cross-Origin-Embedder-Policy
和 Cross-Origin-Opener-Policy
的 report-to
字段中指定的端点将在违反这些政策时收到报告。
您还可以在 Content-Security-Policy-Report-Only
、Cross-Origin-Embedder-Policy-Report-Only
和 Cross-Origin-Opener-Policy-Report-Only
的 report-to
字段中指定在 Reporting-Endpoints
中配置的端点。如果违反了这些政策,他们也会收到举报。
虽然在这两种情况下都会发送报告,但 -Report-Only
标头不会强制执行政策:不会有任何内容被破坏或实际上会被屏蔽,但您将收到有关哪些内容会遭到破坏或被屏蔽的报告。
ReportingObserver
ReportingObserver
JavaScript API 可以帮助您观察客户端警告。
ReportingObserver
和 Reporting-Endpoints
标头生成的报告看起来一样,但用例略有不同。
在以下情况下可使用 ReportingObserver
:
- 您只想监控弃用情况和/或浏览器干预的情况。
ReportingObserver
会显示客户端警告(例如弃用和浏览器干预),但与Reporting-Endpoints
不同,它不会捕获任何其他类型的报告,例如 CSP 或 COOP/COEP 违规行为。 - 您需要实时应对这些违规行为。
ReportingObserver
可用于向违规事件附加回调。 - 您想要通过自定义回调向报告附加其他信息以帮助进行调试。
另一个区别在于,ReportingObserver
仅在客户端配置:即使您无法控制服务器端标头且无法设置 Reporting-Endpoints
,也可以使用它。
深入阅读
主打图片,创作者:Nine Koepfer / @enka80 在 Unsplash 用户,已编辑。非常感谢 Ian Clelland、Eiji Kitamura 和 Milica Mihajlija 对本文的评价和建议。