附加组件团队最近完成了在 addons.mozilla.org (AMO) 上启用 内容安全策略 (CSP) 的工作。本文旨在介绍实施 CSP 的基础知识,并重点介绍我们在 AMO 上实施 CSP 时遇到的某些问题。
什么是内容安全策略?
内容安全策略 (CSP) 是一种安全标准,旨在帮助防止 跨站点脚本 (XSS) 和其他内容注入攻击。它通过将用户代理加载的内容来源限制为仅限站点运营商允许的来源来实现这一点。
该策略是通过与服务器响应一起发送的标头来实现的。从那里开始,支持的用户代理需要接管该策略并积极阻止检测到的策略违规。
为什么需要它?
CSP 是另一层防御,有助于保护用户免受各种攻击载体的攻击,例如 XSS 和其他形式的内容注入攻击。虽然它不是灵丹妙药,但它确实有助于使攻击者更难注入内容和窃取数据。
安全地构建网站很困难。即使您知道一般 Web 安全最佳实践,仍然很容易忽略某些内容或无意中在原本安全的网站中引入安全漏洞。
CSP 通过限制可以从其加载活动内容和被动内容的来源来起作用。它还可以限制活动内容的某些方面,例如执行内联 JavaScript 和使用eval().
实施 CSP
要实施 CSP,您必须为网站使用的所有类型资源定义允许来源列表。例如,如果您有一个简单的网站,需要加载本地托管的脚本、样式表和图像,以及从 jQuery 库的 CDN 加载,您可以使用以下内容:
Content-Security-Policy:<br> <b>default-src</b> 'self';<br> <b>script-src</b> 'self' https://code.jqueryjs.cn;
在上面的示例中,Content-Security-Policy是 HTTP 标头。您也可以指定Content-Security-Policy-Report-Only,这意味着用户代理将报告错误,但不会积极阻止任何内容。在测试新策略时,这是一个有用的功能。
继承。始终定义default-src非常重要。否则,指令将默认允许所有资源。因为我们有default-src 'self',这意味着从网站域提供的图像也将被允许。
default-src是源指令在未配置时将回退到的特殊指令。但是,以下指令不会从default-src继承,因此请注意这一点,并记住不将它们设置为任何内容意味着它们将被取消设置或使用浏览器的默认设置
- base-uri
- form-action
- frame-ancestors
- plugin-types
- report-uri
- sandbox
将'self'设置为default-src通常是安全的,因为您控制自己的域。但是,如果您确实想默认更严格地锁定内容,您可以使用default-src 'none'并明确列出所有已知的资源类型。鉴于上面的示例,这将导致如下所示的策略:
Content-Security-Policy:<br> <b>default-src</b> 'none';<br> <b>img-src</b> 'self';<br> <b>script-src</b> 'self' https://code.jqueryjs.cn;<br> <b>style-src</b> 'self';
处理内联脚本
CSP 默认情况下不允许内联 JavaScript,除非您明确允许它。这意味着您需要删除以下内容
- <script>页面中的块
- HTML 中的 DOM 事件处理程序,例如onclick
- javascript伪协议。
如果您确实需要允许它,则 CSP 提供了一种通过使用nonce-source或hash-source指令,允许执行特定内容块。您可以通过使用‘unsafe-inline’在script-src指令中选择退出此保护,但强烈建议不要这样做,因为它会使您的网站容易受到 XSS 攻击。
有关nonce-source和hash-source的更多信息,请参阅 我们拥有的 Web CSP。
处理 eval()
CSP 还阻止动态脚本执行,例如
- eval()
- 用作setTimeout / setInterval
- new Function()构造函数
的第一个参数的字符串如果您需要启用此功能,可以使用'unsafe-eval',但同样不建议这样做,因为不受信任的代码很容易潜入块中。
在 AMO 上,我们发现许多库代码都使用 eval 和 new Function,而这部分 CSP 实现是最耗时修复的部分。例如,我们有使用new Function的下划线模板。修复这些问题需要我们迁移到预编译的模板。
处理层叠样式表 (CSS)
CSP 默认情况下不允许
- <style>块
- styleHTML 中的属性
这对我们来说是一个更大的问题。许多库在使用 JavaScript 添加到页面的 HTML 代码段中使用 style 属性,我们在 HTML 模板中直接添加了少量 style 属性。
值得一提的是,如果样式属性是通过 JavaScript 直接更新的,那么您就不会遇到问题。例如,jQuery 的css()方法就可以了,因为它在幕后直接更新了样式属性。但是,您不能在 JS 添加的 HTML 代码块中使用style="background: red"。
与之前一样,如果您需要一种受控的方法来允许选择性地使用内联 CSS,则可以使用nonce-source和hash-source指令。
您可能正在想:“这是 CSS,有什么风险?” 有各种巧妙的方法可以使用 CSS 从网站中窃取数据。例如,使用属性选择器和背景图像,您可以暴力破解和窃取属性敏感数据,例如 CSRF 令牌。有关此问题以及通过 CSS 进行的其他更高级攻击载体的更多信息,请参阅 XSS (No, the _other ‘S’)。
对于'unsafe-inline',不建议用于style-src,但这是权衡风险和消除内联样式所需的更改次数的问题。
报告
最好设置report-uri指令并将其指向某个地方以收集 CSP 违规的 JSON 报告。由于 CSP 目前不会合并错误报告,因此具有多个错误的单个页面会导致向您的报告端点发送多个报告。如果您运营的是拥有大量受众的网站,那么该端点可能会收到大量流量。
除了由实际违规触发的报告之外,您还会发现许多附加组件和浏览器扩展程序会导致 CSP 违规。最终结果是大量噪音:拥有允许对传入数据进行过滤的功能非常推荐。
测试
创建初始策略后,下一步是测试它并修复任何缺失的来源。如果您运营的是大型网站,您可能会对从其提取资源的来源数量感到惊讶。在报告模式下运行网站允许您在它们积极阻止内容之前通过控制台和 CSP 报告来捕获问题。
一旦每个人都确认没有被错误地阻止任何内容,就该强制执行策略了。从那时起,这仅仅是注意任何遗漏的内容并将策略与浏览器对 CSP 中某些新功能的支持保持同步。
实施
在您确定了正常工作的策略后,下一步是配置您的系统以提供 CSP 指令。实施方式因您选择的 Web 服务器软件而异,但它通常看起来像这样
# Enable CSP in Apache
Header set Content-Security-Policy "default-src 'none'; img-src 'self';
script-src 'self' https://code.jqueryjs.cn; style-src 'self'"
# Enable CSP in nginx
add_header Content-Security-Policy "default-src 'none'; img-src 'self';
script-src 'self' https://code.jqueryjs.cn; style-src 'self'";
如果您的服务提供商不提供对您的 Web 服务器配置的控制,请不要惊慌!您仍然可以通过使用meta标签启用 CSP。只需让您的meta标签成为<head>:
<!-- Enable CSP inside the page's HTML -->
<head>
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self';
script-src 'self' https://code.jqueryjs.cn; style-src 'self'">
</head>
中的第一个标签
我们的最终实现
Content-Security-Policy:<br> <b>default-src</b> 'self';<br> <b>connect-src</b> 'self' https://sentry.prod.mozaws.net;<br> <b>font-src</b> 'self' https://addons.cdn.mozilla.net;<br> <b>frame-src</b> 'self' https://ic.paypal.com https://paypal.com<br> https://www.google.com/recaptcha/ https://www.paypal.com;<br> <b>img-src</b> 'self' data: blob: https://www.paypal.com https://#<br> https://addons.cdn.mozilla.net https://static.addons.mozilla.net<br> https://ssl.gstatic.com/ https://sentry.prod.mozaws.net;<br> <b>media-src</b> https://videos.cdn.mozilla.net;<br> <b>object-src</b> 'none';<br> <b>script-src</b> 'self' https://addons.mozilla.org<br> https://www.paypalobjects.com https://apis.google.com<br> https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/<br> https://# https://addons.cdn.mozilla.net;<br> <b>style-src</b> 'self' 'unsafe-inline' https://addons.cdn.mozilla.net;<br> <b>report-uri</b> /__cspreport__
鉴于 AMO 是一个较旧且非常复杂的网站,您可能想知道我们的最终策略是什么样子
哇!正如您想象的那样,进行了大量的测试才能发现 AMO 使用的无数资源。
总结
您的网站越旧,设置和遵守合理的 Content Security Policy 所需的工作就越多。但是,值得花时间,因为它是在深度防御理念的支持下提供的额外安全层。
- 进一步阅读
- 内容安全策略简介,作者 Mike West
- 浏览器对 CSP 的支持
- 内容安全策略 2 级规范
MDN 关于 CSP 的文档
IRC:四月
关于 Stuart Colville
Stuart 是 Firefox 扩展的工程经理。
11 条评论