确保 CSP 能够有效防范 XSS 攻击

内容安全政策 (CSP) 有助于确保在网页中加载的所有内容都受网站所有者信任。CSP 可以缓解跨站脚本攻击 (XSS),因为它们可以阻止攻击者注入的不可信脚本。但是,如果 CSP 不够严格,则很容易被绕过。如需了解详情,请参阅通过严格的内容安全政策 (CSP) 防范跨站脚本攻击 (XSS)。Lighthouse 会收集对主文档强制执行的 CSP,并报告 CSP 评估器中的问题(如果可以绕过)。

Lighthouse 报告警告,在强制模式下找不到任何 CSP。
Lighthouse 报告警告称,在强制模式下找不到任何 CSP。

不可绕过的 CSP 的必需做法

请实施以下做法,确保您的 CSP 无法被绕过。如果可以绕过 CSP,Lighthouse 会发出严重程度较高的警告。

CSP 针对 XSS 进行防范

如需定位到 XSS,CSP 应包含 script-srcobject-srcbase-uri 指令。CSP 还应不含语法错误。

script-srcobject-src 分别可保护页面免受不安全脚本和不安全插件的侵害。或者,您也可以使用 default-src 配置宽泛的政策,以替代 许多指令,包括 script-srcobject-src

base-uri 可防止注入未经授权的 <base> 标记,这些标记可用于将所有相对网址(例如脚本)重定向到攻击者控制的网域。

CSP 使用 Nonce 或哈希来避免绕过许可名单

script-src 配置许可名单的 CSP 假定来自受信任网域的所有响应都是安全的,并且可以作为脚本执行。不过,对于现代应用,这种假设并不适用;一些常见的良性模式(例如公开 JSONP 接口托管 AngularJS 库的副本)会让攻击者逃脱 CSP 的限制。

在实践中,虽然应用作者可能并不清楚,但大多数 script-src 许可名单都可以被利用 XSS 漏洞的攻击者规避,并且对脚本注入几乎没有保护作用。相比之下,基于 Nonce 和基于哈希的方法不会出现这些问题,并且可以更轻松地采用和维护更安全的政策。

例如,以下代码使用托管在受信任网域上的 JSONP 端点注入攻击者控制的脚本:

CSP:

script-src https://trusted.example.com

HTML:

<script src="https://trusted.example.com/path/jsonp?callback=alert(document.domain)//"></script>

为避免被绕过,CSP 应使用 Nonce 或哈希逐一允许脚本,并使用“strict-dynamic”而非许可名单。

有关安全 CSP 的其他建议

请实现以下做法,以提高安全性和兼容性。如果 CSP 未遵循其中一条建议,Lighthouse 将发出中度严重程度的警告。

配置 CSP 报告

配置报告目的地有助于监控是否存在任何中断。您可以使用 report-urireport-to 指令设置报告目的地。目前,并非所有新型浏览器都支持 report-to,因此建议同时使用这两种方法或仅使用 report-uri

如果任何内容违反 CSP,浏览器会向配置的目的地发送报告。请确保您已在此目标位置配置了用于处理这些报告的应用。

在 HTTP 标头中定义 CSP

您可以在元标记中定义 CSP,如下所示:

<meta http-equiv="Content-Security-Policy" content="script-src 'none'">

不过,如果可以的话,您应在 HTTP 响应标头中定义 CSP。在元标记之前注入内容会绕过 CSP。此外,元标记 CSP 不支持 frame-ancestorssandbox 和报告。

确保 CSP 向后兼容

并非所有浏览器都支持 CSP nonce/hash,因此建议您添加 unsafe-inline 作为不合规浏览器的后备选项。如果浏览器支持 Nonce/Hash,则会忽略 unsafe-inline

同样,并非所有浏览器都支持 strict-dynamic。建议将许可名单设置为任何不合规浏览器的后备选项。在支持 strict-dynamic 的浏览器中,系统会忽略许可名单。

如何制定严格的 CSP

以下示例展示了如何将严格的 CSP 与基于 Nonce 的政策搭配使用。

CSP:

script-src 'nonce-random123' 'strict-dynamic' 'unsafe-inline' https:;
object-src 'none';
base-uri 'none';
report-uri https://reporting.example.com;

HTML:

<script nonce="random123" src="https://trusted.example.com/trusted_script.js"></script>

random123 是每次网页加载时服务器端生成的任何 base64 字符串。由于 Nonce 和 strict-dynamicunsafe-inlinehttps: 在现代浏览器中会被忽略。如需详细了解如何采用严格 CSP,请参阅严格 CSP 指南

您可以使用 Lighthouse 和 CSP 评估程序检查 CSP 是否存在潜在的绕过方法。如果您想测试新的 CSP,但不希望破坏现有网页,请使用 Content-Security-Policy-Report-Only 作为标头名称,以报告模式定义 CSP。这会将 CSP 违规情况发送到您使用 report-toreport-uri 配置的任何报告目的地,但实际上不会强制执行 CSP。