什么是 CSP?为何以及如何将其添加到您的网站。
跨站脚本 (XSS) 糟透了!XSS 是指有人通过评论、表单、广告或 JavaScript 构建中的 NPM 包,将 JavaScript 或 CSS 偷偷带入你的网站。现在,他们掌握了所有访问你网站的用户的账户。XSS 是一种非常常见的攻击,OWASP 声称每 3 个网站和应用中就有 2 个会遭遇这种攻击。
您可以使用 CSP(内容安全策略)来消除大多数 XSS 攻击。CSP 允许您列出允许的外部和内部脚本、样式、图像和其他内容源。它甚至兼容所有主流浏览器。
既然 CSP 可以拦截已知的最常见攻击之一,你以为每个人都会使用它吗?不是的!访问量最大的一百万个网站中,只有不到 2.5% 使用它。

对于大多数网站来说,安全都是事后才考虑的,直到有人窃取了他们的所有数据。然后公众在社交媒体上愤怒不已。典型的公司反应是解雇员工,并承诺将安全放在首位,同时在背后祈祷安全。
让我们看看如何才能避免这样的混乱。
如何添加 CSP 策略
第一步是向您的服务器配置添加一个标头。建议从尽可能严格的 CSP 规则开始,但将其设置为“仅报告”模式。这会创建一份报告,说明如果我们屏蔽所有可能的流量,将会发生什么情况。获得报告后,您就可以开始选择要允许的项目(也称为白名单)、要为哪些项目创建备用修复程序以及要屏蔽哪些项目。
以下是建议的起始标题:
Content-Security-Policy-Report-Only: default-src 'none'; form-action 'none'; frame-ancestors 'none';
在浏览器的开发人员工具中查看您的页面时,您的 CSP 应该与其他标题一起出现。
如果我们没有将其设置为报告模式,您将看到“CSP 的全部威力!”换句话说,CSP 会阻止您的大部分网站。
请记住,内容安全策略 (CSP) 的作用是阻止所有您不允许的内容。
如果你在浏览器开发者工具(F12)中打开控制台,通常会看到很多错误。第一个错误可能会提示缺少 report-uri,但我们稍后会讨论这个问题。其余错误都应该以 [Report Only] 开头。这是 CSP 报告模式,它会告诉你哪些内容会被拦截以及如何允许拦截。
CSS样式表通常是最先出现的错误之一。它看起来像这样:
[Report Only] Refused to load the stylesheet 'https://example.com/style.css' because it violates the following Content Security Policy directive: "default-src 'none'". Note that 'style-src' was not explicitly set, so 'default-src' is used as a fallback.
为了解决这个问题,我们调整了策略,添加了允许“self”的 style-src 指令。添加“self”允许我们包含任何与页面托管在同一 URL 和端口号上的 CSS 样式表。如果不这样做,style-src 将默认使用我们已设置为 none 的 default-src 指令。
Content-Security-Policy-Report-Only: default-src 'none'; form-action 'none'; frame-ancestors 'none'; style-src 'self';
您很可能还想在图像和脚本中添加“self”。这将导致再次调整我们的 CSP。
Content-Security-Policy-Report-Only: default-src 'none'; form-action 'none'; frame-ancestors 'none'; style-src 'self'; script-src 'self'; img-src 'self';
典型的网站也需要依赖外部脚本。我们可以通过修改 script-src 指令来允许来自域名cdnjs.com的 JavaScript 运行。
Content-Security-Policy-Report-Only: default-src 'none'; form-action 'none'; frame-ancestors 'none'; style-src 'self'; script-src 'self' cdnjs.com; img-src 'self';
看到我们当前的规则,你可能会想,为什么我们要明确声明 form-action 和 frame-ancestors 的指令?它们是特殊情况,不使用 default-src 后备。
您可以在MDN上找到完整的指令列表。
内联脚本是我的中间名
内联 JavaScript 和 CSS 在网站上经常使用,但它们也很危险。它们是黑客发起 XSS 攻击的最简单方法。因此,要允许它们,您必须在'unsafe-inline'
要允许它们的指令中添加。这是为了确保您了解自己正在做什么,不建议这样做。
一种常见的 CSS 模式是将渲染“首屏内容”的最重要的 CSS 代码与<style>
标签内联。这有助于减少感知到的渲染时间。对于HTTP/2,我通常不建议这样做,因为它通常会更慢。如果您选择使用内联脚本,则有三种选择。
- 获取脚本的 SHA-256 哈希值并将其添加到我们的 CSP 中。Chrome 的开发者工具甚至会在控制台显示 CSP 错误时为您生成 SHA-256 哈希值。将其添加到我们当前的 CSP 示例中如下所示:
Content-Security-Policy-Report-Only: default-src 'none'; form-action 'none'; frame-ancestors 'none'; style-src 'self'; script-src 'self' cdnjs.com sha256-c2u0cNUv1GcIb92+ybgJ4yMPatX/k+xxHHbugKVGUU8=; img-src 'self';
-
您的服务器会为每个内联脚本生成一个唯一的 nonce。这意味着每个服务器请求都必须生成一个新的 nonce。您可以像 SHA-256 一样将其添加到您的 CSP 中
nonce-47c2gtf3a1
。您还需要将其添加到脚本标签中:<script nonce="47c2gtf3a1">
。由于 nonce 的实现相当不方便,因此很少使用。 -
在你的策略中添加允许内联脚本
'unsafe-inline'
,然后羞愧地低下头去。这允许内联脚本,会削弱你的内容安全策略 (CSP) 并允许 XSS 攻击。这样做应该会让你感到难过。
加油!不安全的内联代码不会是世界末日!就你一家。(开个玩笑,算了……)
首次实现内容安全策略 (CSP) 时,很可能需要在 style-src 或 script-src 指令上使用 unsafe-inline。你甚至可能需要使用 unsafe-eval 来允许 JavaScript 的 eval 函数。真是的!
请记住,CSP 应该是您安全武器库中的众多武器之一,而不是唯一的武器。
拥有包含少量不安全规则的 CSP 仍然比完全没有 CSP 要好。完全不实现 CSP 就等于设置所有指令都允许所有不安全的 CSP 规则。
例如,使用 CSS 窃取登录信息的常见方法是向恶意 URL(例如,您在密码登录字段中输入的字母在http://evilexamplesite.com?password=a
哪里)发送背景图片或字体的请求a
。当您输入密码的下一个字母时,恶意的 CSS 脚本会发送另一个请求,但发送的是该字母而不是a
。然后,恶意网站会记录这些请求以确定您的用户名和密码。通过允许我们的 style-src 使用 unsafe-inline,有人可以注入这段恶意代码。幸运的是,他们的代码无法运行,因为我们的 CSP 不允许来自恶意示例网站的 img-src 和 font-src。
你这样做也并非是与坏人为伍。很多网站,包括GitHub和安全专家Troy Hunt 的博客,都使用了 unsafe-inline。Facebook 也使用了 unsafe-eval,甚至要求其部分 SDK 也必须使用它。任何使用 Google Tag Manager 进行分析的人也必须降低其 CSP 安全性。我也必须承认这一点。我的个人博客使用GatsbyJS,在移除 unsafe-inline 之前,有一些问题需要修复。
如果您仍然因为不得不在指令上实施不安全的规则而感到沮丧,可以尝试在网站的每个页面上应用不同的 CSP 标头。如果您有允许或显示来自用户或外部来源的输入的区域,您可以尝试在这些页面上添加更严格的 CSP。
生成 CSP 的其余部分
传统的方法是访问你网站的每个页面,检查这些错误并修复它们。如果你有时间这样做,那就太好了!你甚至可能会喜欢这个很棒的Chrome 扩展程序或Fiddler 扩展程序。它们可以让你浏览你的网站,并为你生成合适的内容安全策略 (CSP)。
一年多前,我第一次接触 CSP 时,觉得这项任务对我来说太难完成了。直到那时,我才了解到report-uri
CSP 的功能。你可以在 CSP 末尾添加report-uri
一个 URL,用于发送报告。浏览器会将任何违反 CSP 的行为发送到你指定的 URL。现在,你的访客只需使用你的网站,就能为你完成所有工作。
以下是浏览器发送的错误示例:
{
"csp-report": {
"document-uri": "https://mattferderer.com/",
"referrer": "",
"violated-directive": "script-src",
"effective-directive": "script-src",
"original-policy": "default-src 'none'; form-action 'none'; frame-ancestors 'none'; report-uri https://mattferderer.report-uri.com/r/d/csp/wizard",
"disposition": "report",
"blocked-uri": "inline",
"line-number": 4,
"source-file": "https://mattferderer.com/",
"status-code": 0,
"script-sample": ""
}
}
该报告会让您了解发生了什么事以及在哪里发生。
如果您已经有错误日志服务,可以使用它。如果您正在寻找一种免费且简单的入门方法,我推荐使用Report URI。
Tala Security的优秀员工运营着类似的服务,他们不久前向我指出,CSP 并非一个设置好就忘掉的工具。随着您的网站或您所依赖的服务更新,您的 CSP 可能需要进行调整。这使得报告服务更具价值。
拥有报告服务还将向您显示运行不同浏览器、浏览器扩展等的用户的真实数据。
我建议您在“仅报告”模式下运行您的 CSP,并将报告发送到服务,直到您确信没有阻止任何有价值的内容发送给用户。完成后,您可以将 CSP 从 更改为Content-Security-Policy-Report-Only
。Content-Security-Policy
这将开始强制执行您的 CSP。您仍然可以将 report-uri 保留为 CSP 的一部分,以继续收集错误。
快速入门指南
以下是有关如何开始的简要回顾,其中包含使用报告 URI 的附加说明。
-
为您的网站添加严格的 CSP 标头。我建议
Content-Security-Policy-Report-Only: default-src 'none'; form-action 'none'; frame-ancestors 'none';
-
在Report URI注册一个免费账户。请务必验证您的邮箱。否则,服务将无法正常使用。
-
使用报告 URI,前往“设置”并创建 CSP 报告地址。将该报告地址添加到您的 CSP:
Content-Security-Policy-Report-Only: default-src 'none'; form-action 'none'; frame-ancestors 'none'; report-uri https://yoursite.report-uri.com/r/d/csp/reportOnly
-
使用报告 URI,转到 CSP > 我的策略。添加新策略。
-
使用“报告 URI”,前往“云服务策略管理 (CSP)”>“向导”。您可以实时监控数据。*您可以在此处为每个指令允许或屏蔽一个网站。这将自动生成您的策略。您可以返回“我的策略”查看。
-
使用报告 URI 生成的新策略更新您的 CSP。
-
一旦您在仅报告模式下运行了 CSP,并且对报告 URI 中缺少新条目感到满意,请调整您的 CSP,从
Content-Security-Policy-Report-Only
到Content-Security-Policy
开始强制执行您的 CSP。
*根据您的报告服务,违反 CSP 策略的内联脚本可能不会显示。
附加说明
Twitter 为 Ruby on Rails 开发者提供了一个很棒的软件包,用于设置安全的默认标头。他们还列出了其他流行框架的类似库。
GitHub 的 CSP Journey是一篇关于他们在实施 CSP 时遇到的问题的精彩文章。
此CSP 快速参考指南和 Scott Helme 的CSP 备忘单是实施 CSP 时值得一看的优秀资源。
如果您需要对特定页面采取额外的预防措施,请查看沙盒模式。
最初发布于mattferderer.com。
文章来源:https://dev.to/mattferderer/what-is-csp-why--how-to-add-it-to-your-website-28df