CSP(Content Security Policy) 101

2020-12-04  本文已影响0人  anOnion

这期科普网络安全里的一个小知识:Content Security Policy(内容安全策略)。

前言

我们都应该听说过XSS(跨站脚本攻击);它可能是最常见、危害最大的网络安全漏斗。大约十年前吧,W3C 网络应用安全工作组为防御 XSS、点击劫持等代码注入攻击,推荐 CSP 成为计算机安全标准,以阻止恶意内容在受信网页环境中执行;之后几乎所有的现代浏览器都支持了这一策略。

XSS 可以通过本站点<script>脚本、内联 JS 代码、外部导入资源等等方式进行注入攻击。CSP 根据这一特性,启用白名单策略,过滤所有执行过程中加载的资源。效果就是:打开浏览器控制台还可以看到如下字样:

Refused to load the script 'http://xxxxx' because it violates the following Content Security Policy directive: "script-src 'self' 'unsafe-eval' 'unsafe-inline'

CSP

如下所示,CSP 本质上就是一个很长的字符串,利用 ; 隔开了各个策略:

Content-Security-Policy: style-src 'unsafe-inline' 'self'; script-src blob: 'unsafe-inline' 'self';

每个策略又是一组通过 空格 隔开的字符串,第一个字符串表示限制指令(如 script-src),之后的字符串就是限制的选项值(如'self'https://fonts.googleapis.com)。

限制指令

常见的限制指令(directive)有:

指令 限制资源
script-src 外部资源、内联脚本、eval 函数
style-src css 文件
media-src video,audio,以及关联的 text 文本
img-src 图像
frame-src iframe
default-src 所有上述指令的默认值

选项值

限制选项可细分为三类:

  1. 关键字(需加单引号):

    • 'self':匹配所有同源资源
    • 'none':阻止所有该指令下列举的资源
  2. 常用资源:

    • url 或是带通配符的 url,如:https://*.unpkg.com
    • 协议名(有冒号):如:https:blob:
  3. script-src的特殊值(都需要加引号):

    • 'unsafe-eval':允许 eval 方法
    • 'unsafe-inline':允许内联的<script>脚本执行
    • 'nonce-<base64>'<script>带有特定的 nonce 值才能执行
    • '<hash-algorithm>-<base64>'<script>脚本的 hash 值为特定值时才能执行

例子

上文列出了最常用的 CSP 指令,看完可能还在云里雾里,我再用几个具体的例子解释一下:

例 1

只允许本站的 js 脚本:

Content-Security-Policy: script-src 'self';

例 2

允许本站和来自 unpkg.com 的脚本,以及所有图片:

Content-Security-Policy: script-src 'self' *.unpkg.com; img-src *;

例 3

阻止所有 iframe 窗口;并允许其他所有本站资源:

Content-Security-Policy: frame-src 'none';default-src 'self';

例 4

执行特定 nonce 的内联脚本:

Content-Security-Policy: script-src 'nonce-EfNBf03nceIOAn39fn389h3sdfa' 'self';

只有在<script>标签内带有特定 nonce 值的脚本方能执行:

<script nonce="nonce-EfNBf03nceIOAn39fn389h3sdfa" src="./hello.js" />

nonce 比较常用的场景有:

  1. 设置为 token 值,只有获取了特定 token,才有权限加载特定资源
  2. webpack 可以在入口文件设置__webpack_nonce__变量,为每个唯一的页面视图生成和提供一个唯一的基于 hash 的 nonce 值

例 5

Hash 值相符的脚本才能执行:

Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG+HiZ1guq6ZZDob/Tng='

这里说明一下 alert('Hello, world.'); 这个字符串sha256 值为 sha256-qznLcsROx4GACP2dm0UCKCzCG+HiZ1guq6ZZDob/Tng=,所以只有如下代码能执行:

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

Hash 值在前端开发中也可配在 webpack 里,有csp-html-webpack-plugin这种插件会自动在 meta 和 script 里生成 hash 值,以控制不同版本的脚本文件。

使用方法

上面列举了一些常用的配置场景,忘了提 CSP 到底怎么使用了。有两种方法可以启用 CSP 策略:

  1. 在服务器返回的 HTTP header 里加上Content-Security-Policy字段,以 express 为例:

    app.use((req, res, next) => {
      const csp = "default-src 'self';";
      res.append("Content-Security-Policy", csp);
      next();
    });
    
  2. html 里加上 <meta> 标签,这个现在基本可以用 webpack 来完成了:

    // index.html
    <meta http-equiv="Content-Security-Policy" content="default-src 'self';" />
    

小结

CSP 是过滤 XSS 攻击最常用的手段,我们相关从业人员都应该懂得这些基本用法。但是 CSP 也只是最基本的防御手段,只要控制了一台列入了白名单的可信主机,基本 CSP 就凉凉了。所以,网络安全需要更多的防护手段综合治理,任重道远呀。

上一篇下一篇

猜你喜欢

热点阅读