内容安全策略(CSP)_防护_XSS_攻击的好助手

原文连接php

摘要: 什么是 CSP? 其核心思想十分简单:网站经过发送一个 CSP 头部,来告诉浏览器什么是被受权执行的与什么是须要被禁止的。 这里有一个 PHP 的例子: <?php header("Content-Security-Policy: <your directives>"); ?> 一些指令 你能够定义一些全局规则或者定义一些涉及某一类资源的规则: default-src 'self' ; # self = 同端口,同域名,同协议 => 容许 基础参数是 default-src:若是没有为某一类资源设置指令规则,那么浏览器就会使用这个默认参数值。css

什么是 CSP?

其核心思想十分简单:网站经过发送一个 CSP 头部,来告诉浏览器什么是被受权执行的与什么是须要被禁止的。前端

这里有一个 PHP 的例子:web

 
 
  1. <?php
  2. header("Content-Security-Policy: <your directives>");
  3. ?>

一些指令

你能够定义一些全局规则或者定义一些涉及某一类资源的规则:数据库

 
 
  1. default-src 'self' ;
  2. # self = 同端口,同域名,同协议 => 容许

基础参数是 default-src:若是没有为某一类资源设置指令规则,那么浏览器就会使用这个默认参数值。json

 
 
  1. script-src 'self' www.google-analytics.com ;
  2. # 来自这些域名的 JS 文件 => 容许

在这个例子中,咱们已经受权了 www.google-analytics.com 这个域名来源的 JavaScript 文件使用到咱们的网站上。咱们也添加了 'self' 这个关键词;若是咱们经过 script-src 来从新设置其它的规则指令,它将会覆盖 default-src 规则。小程序

若是没有指明协议(scheme)或端口,它就会强制选择与当前页面相同的协议或端口。这样作防止了混合内容(LCTT 译注:混合内容指 HTTPS 页面中也有非 HTTPS 资源,可参见: https://developer.mozilla.org/zh-CN/docs/Security/MixedContent )。若是页面是 https://example.com,那么你将没法加载 http://www.google-analytics.com/file.js 由于它已经被禁止了(协议不匹配)。然而,有一个例外就是协议的提高是被容许的。若是 http://example.com 尝试加载 https://www.google-analytics.com/file.js,接着协议或端口容许被更改以便协议的提高。浏览器

 
 
  1. style-src 'self' data: ;
  2. # Data-Uri 嵌入 CSS => 容许

在这个例子中,关键词 data: 受权了在 CSS 文件中 data 内嵌内容。安全

在 CSP 1 规范下,你也能够设置以下规则:app

  • img-src 有效的图片来源
  • connect-src 应用于 XMLHttpRequest(AJAX),WebSocket 或 EventSource
  • font-src 有效的字体来源
  • object-src 有效的插件来源(例如,<object><embed><applet>
  • media-src 有效的 <audio> 和 <video> 来源

CSP 2 规范包含了以下规则:

  • child-src 有效的 web workers 和 元素来源,如 <frame> 和 <iframe> (这个指令用来替代 CSP 1 中废弃了的 frame-src 指令)
  • form-action 能够做为 HTML <form> 的 action 的有效来源
  • frame-ancestors 使用 <frame><iframe><object><embed> 或 <applet> 内嵌资源的有效来源
  • upgrade-insecure-requests 命令用户代理来重写 URL 协议,将 HTTP 改到 HTTPS (为一些须要重写大量陈旧 URL 的网站提供了方便)。

为了更好的向后兼容一些废弃的属性,你能够简单的复制当前指令的内容同时为那个废弃的指令建立一个相同的副本。例如,你能够复制 child-src 的内容同时在 frame-src 中添加一份相同的副本。

CSP 2 容许你添加路径到白名单中(CSP 1 只容许域名被添加到白名单中)。所以,相较于将整个 www.foo.com 域添加到白名单,你能够经过添加 www.foo.com/some/folder 这样的路径到白名单中来做更多的限制。这个须要浏览器中 CSP 2 的支持,但它很明显更安全。

一个例子

我为 Web 2015 巴黎大会上个人演讲 “CSP in Action”制做了一个简单的例子。

在没有 CSP 的状况下,页面展现以下图所示:

不是十分优美。要是咱们启用了以下的 CSP 指令又会怎样呢?

 
 
  1. <?php
  2. header("Content-Security-Policy:
  3. default-src 'self' ;
  4. script-src 'self' www.google-analytics.com stats.g.doubleclick.net ;
  5. style-src 'self' data: ;
  6. img-src 'self' www.google-analytics.com stats.g.doubleclick.net data: ;
  7. frame-src 'self' ;");
  8. ?>

浏览器将会做什么呢?它会(很是严格的)在 CSP 基础规则之下应用这些指令,这意味着任何没有在 CSP 指令中被受权容许的都将会被禁止(“blocked” 指的是不被执行、不被显示而且不被使用在网站中)。

在 CSP 的默认设置中,内联脚本和样式是不被受权的,意味着每个 <script>onclick 事件属性或style 属性都将会被禁止。你可使用 style-src 'unsafe-inline' ; 指令来受权使用内联 CSS。

在一个支持 CSP 的现代浏览器中,上述示例看起来以下图:

发生了什么?浏览器应用了指令而且拒绝了全部没有被受权的内容。它在浏览器调试终端中发送了这些通知:

若是你依然不肯定 CSP 的价值,请看一下 Aaron Gustafson 文章 “More Proof We Don't Control Our Web Pages”。

固然,你可使用比咱们在示例中提供的更严格的指令:

  • 设置 default-src 为 'none'
  • 为每条规则指定你的设置
  • 为请求的文件指定它的绝对路径

更多关于 CSP 的信息

支持

CSP 不是一个须要复杂的配置才能正常工做的每日构建特性。CSP 1 和 2 是候选推荐标准!浏览器能够很是完美的支持 CSP 1

CSP 2 是较新的规范,所以对它的支持会少那么一点。

如今 CSP 3 仍是一个早期草案,所以尚未被支持,可是你依然可使用 CSP 1 和 2 来作一些重大的事。

其余须要考虑的因素

CSP 被设计用来下降跨站脚本攻击(XSS)的风险,这就是不建议开启内联脚本和 script-src 指令的缘由。Firefox 对这个问题作了很好的说明:在浏览器中,敲击 Shift + F2 而且键入 security csp,它就会向你展现指令和对应的建议。这里有一个在 Twitter 网站中应用的例子:

若是你确实须要使用内联脚本和样式的话,另外一种可能就是生成一份散列值。例如,咱们假定你须要使用以下的内联脚本:

 
 
  1. <script>alert('Hello, world.');</script>

你应该在 script-src 指令中添加 sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng= 做为有效来源。这个散列值用下面的 PHP 脚本执行得到的结果:

 
 
  1. <?php
  2. echo base64_encode(hash('sha256', "alert('Hello, world.');", true));
  3. ?>

我在前文中说过 CSP 被设计用来下降 XSS 风险,我还得加上“……与下降未经请求内容的风险。”伴随着 CSP 的使用,你必须知道你内容的来源是哪里与它们在你的前端都做了些什么(内联样式,等)。CSP 同时能够帮助你让贡献者、开发人员和其余人员来遵循你内容来源的规则!

如今你的问题就只是,“不错,这很好,可是咱们如何在生产环境中使用它呢?”

如何在现实世界中使用它

想要在第一次使用 CSP 以后就失望透顶的方法就是在生产环境中测试。不要想固然的认为,“这会很简单。个人代码是完美而且至关清晰的。”不要这样做。我这样干过。相信我,这至关的蠢。

正如我以前说明的,CSP 指令由 CSP 头部来激活,这中间没有过渡阶段。你偏偏就是其中的薄弱环节。你可能会忘记受权某些东西或者遗忘了你网站中的一小段代码。CSP 不会饶恕你的疏忽。然而,CSP 的两个特性将这个问题变得至关的简单。

report-uri

还记得 CSP 发送到终端中的那些通知么?report-uri 指令能够被用来告诉浏览器发送那些通知到指定的地址。报告以 JSON 格式送出。

 
 
  1. report-uri /csp-parser.php ;

所以,咱们能够在 csp-parser.php 文件中处理有浏览器送出的数据。这里有一个由 PHP 实现的最基础的例子:

 
 
  1. $data = file_get_contents('php://input');
  2. if ($data = json_decode($data, true)) {
  3. $data = json_encode(
  4. $data,
  5. JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES
  6. );
  7. mail(EMAIL, SUBJECT, $data);
  8. }

这个通知将会被转换成为一封邮件。在开发过程当中,你可能不会须要比这更复杂的其它东西。

对于一个生产环境(或者是一个有较多访问的开发环境),你应该使用一种比邮件更好的收集信息的方式,由于这种方式在节点上没有验证和速率限制,而且 CSP 可能变得乱哄哄的。只需想像一个会产生 100 个 CSP 通知(例如,一个从未受权来源展现图片的脚本)而且天天会被浏览 100 次的页面,那你就会天天收到 10000 个通知啊!

例如 report-uri.io 这样的服务能够用来简化你的通知管理。你也能够在 GitHub上看一些另外的使用report-uri (与数据库搭配,添加一些优化,等)的简单例子。

report-only

正如咱们所见的,最大的问题就是在使用和不使用 CSP 之间没有中间地带。然而,一个名为 report-only 的特性会发送一个稍有不一样的头部:

 
 
  1. <?php
  2. header("Content-Security-Policy-Report-Only: <your directives>");
  3. ?>

总的来讲,这个头部就是告诉浏览器,“表现得彷佛全部的 CSP 指令都被应用了,可是不由止任何东西。只是发送通知给本身。”这是一种至关棒的测试指令的方式,避免了任何有价值的东西被禁止的风险。

在 report-only 和 report-uri 的帮助下你能够毫无风险的测试 CSP 指令,而且能够实时的监控网站上一切与 CSP 相关的内容。这两个特性对部署和维护 CSP 来讲真是至关的有用!

结论

为何 CSP 很酷

CSP 对你的用户来讲是尤为重要的:他们在你的网站上再也不须要遭受任何的未经请求的脚本,内容或 XSS 的威胁了。

对于网站维护者来讲 CSP 最重要的优点就是可感知。若是你对图片来源设置了严格的规则,这时一个脚本小子尝试在你的网站上插入一张未受权来源的图片,那么这张图片就会被禁止,而且你会在第一时间收到提醒。

开发者也须要确切的知道他们的前端代码都在作些什么,CSP 能够帮助他们掌控一切。会促使他们去重构他们代码中的某些部分(避免内联函数和样式,等)而且促使他们遵循最佳实践。

如何让 CSP 变得更酷

讽刺的是,CSP 在一些浏览器中过度的高效了,在和书签栏小程序一块儿使用时会产生一些 bug。所以,不要更新你的 CSP 指令来容许书签栏小程序。咱们没法单独的责备任何一个浏览器;它们都有些问题:

  • Firefox
  • Chrome (Blink)
  • WebKit

大多数状况下,这些 bug 都是禁止通知中的误报。全部的浏览器提供者都在努力解决这些问题,所以咱们能够期待很快就会被解决。不管怎样,这都不会成为你使用 CSP 的绊脚石。

原文连接

相关文章
相关标签/搜索