解读CSP策略

CSP,全称为 content security policy,即内容安全策略。

描述

它是一套应用在浏览器端的策略,通过限制网页引入资源,防止一些跨站攻击、点击劫持或者其他代码注入。
通俗讲就是可以设置一个白名单,包含了网页加载JS、CSS、图片、视频甚至Ajax请求的源头(域名等信息),不在白名单里的,将会被浏览器禁止加载。

原理

浏览器厂商对CSP策略进行了实现,现代浏览器基本都支持Level 1策略,最新的浏览器对Level 2的部分内容支持较好。

CSP字段内容

CSP 的定义格式如下:

Content-Security-Policy: 指令 内容源;

例如:

Content-Security-Policy: default-src ‘none’;
default-src 是指令,’none’ 是值。

Content-Security-Policy: default-src ‘none’; script-src http://*.apptranz.com;
指令与值之间用空格分割,指令与指令之间需要有分号分割。

CSP指令

  • default-src: 对JavaScript, CSS, 图片, 字体, AJAX请求, frame/iframe, HTML5 媒体文件等进行默认定义。
  • frame-src :定义iframe的内容源(CSP Level 1)
  • child-src :定义iframe的内容源(CSP Level 2)
  • frame-ancestors :定义iframe、embed、object等内容源(CSP Level 2)
  • connect-src :定义XMLHttpRequest、WebSocket、EventSource源
  • font-src :定义字体源
  • img-src :定义图片、svg、base64资源
  • media-src :定义video、audio等资源
  • object-src: 定义embed、object等资源
  • script-src: 定义脚本引用源
  • style-src:定义样式表引用源
  • form-action:定义表单提交源(CSP Level 2)
  • referrer:定义网页referrer源(CSP Level 2)
  • sandbox:限制浏览器行为,比如不能弹出等
    更多指令可以参考CSP文档

这里着重提一下default-src:
default-src 是默认指令,也就是当其他类型的指令没有设置时,浏览器会自动查找default-src中设置的源列表。
例如:

Content-Security-Policy: default-src ‘none’; script-src http://*.apptranz.com;
当访问图片资源时,由于以上没定义img-src,所以浏览器会查询default-src中的定义。此时default-src为’none’,表示不允许加载任何源。因此对任何图片资源访问都会失败。

default-src 与其他已定义内容互斥。
例如:

Content-Security-Policy: default-src ‘http://.evshot.com’; img-src http://.apptranz.com;
访问图片资源时,浏览器只根据img-src源列表加载内容,忽略default-src。

再介绍一些特殊的指令
* block-all-mixed-content: 使用HTTPS访问的页面强制不加载HTTP资源

  • upgrade-insecure-requests: 自动将网页上所有外部资源的HTTP请求替换成HTTPS请求。这个设置目前只有Chrome支持,不建议使用。

  • report-uri:可以规定一个行为上报的地址,比如:

    Content-Security-Policy: default-src ‘self’; …; report-uri /csp_report_parser;
    浏览器会通过POST向服务端发一个JSON

{
    "csp-report": {
    "document-uri": "http://example.org/page.html",
    "referrer": "http://evil.example.com/",
    "blocked-uri": "http://evil.example.com/evil.js",
    "violated-directive": "script-src 'self' https://apis.google.com",
    "original-policy": "script-src 'self' https://apis.google.com; report-uri http://example.org/my_amazing_csp_report_parser"
    }
}

上面的指令,如果配合 Content-Security-Policy-Report-Only 这一个header设置,将会只上报信息,不会实际执行CSP策略。这有助于在设置CSP之前了解CSP设置带来的问题。

Content-Security-Policy-Report-Only: default-src ‘self’; …; report-uri /csp_report_parser;

源列表

源列表就是定义指令的值。
* *:通配符,允许任何URL,除了data: blob: filesystem:
* ‘none’:禁止访问任何源
* ‘self’:只能访问同源(同源策略包括协议、主机名、端口)
* data:允许base64协议编码的内容(比如图片经过base64编码的资源形式)
* domain.example.com:允许指定的域名
* *.example.com: 允许含通配符的子域名
* https://cdn.com:允许规定了https协议的域名
* https:: 允许https协议
* ‘unsafe-inline’:允许在html元素行内引入的样式、onclick或者 script标签定义的行内JS
* ‘unsafe-eval’:允许eval执行脚本
* ‘nonce-‘: 允许script或style标签定义的内容,即是unsafe-inline的例外。
* ‘sha256-‘ 如果JS代码编码成哈希值与定义的sha256-规定的一致,那么也可以执行。这种定义通常是特例中的特例。比如:sha256-qznLcsROx4GACP2dm0UCKCzCG+HiZ1guq6ZZDob/Tng= ,允许 alert(‘Hello, world.’); 执行

以下是一些组合例子:

Content-Security-Policy: default-src ‘none’; script-src ‘self’; connect-src ‘self’; img-src ‘self’; style-src ‘self’;
Content-Security-Policy: script-src ‘self’ www.google-analytics.com ajax.googleapis.com;
Content-Security-Policy: default-src ‘self’ www.baidu.com; script-src ‘unsafe-inline’;
定义源列表要注意,每个值之间要用空格分割。与下一个指令之间要有分号分割。

CSP设置方法

CSP策略需要在请求header信息中设置,或者在HTML头部的meta信息中设置:

// PHP 中使用header设置页面头信息
header("Content-Security-Policy: default-src 'none'; ");

//HTML中可设置meta信息

兼容性

在浏览器头信息中设置CSP,有以下写法。

推荐使用 Content-Security-Policy 设置头信息。

绕过CSP

虽然魔高一尺,道高一丈,CSP也有不足。
1、meta跳转
虽然限制了JS等脚本源,依然可以通过设置meta来跳转。至于这meta怎么被第三者设置,就看服务端和传输是否安全。

2、行内脚本
当script-src 配置了unsafe-inline,即允许行内写脚本,那么只需要篡改页面,也能达到目的。

3、link标签
CSP不覆盖 link 标签的预加载请求,什么是link预加载呢?

<link rel="prefetch" href="http://www.example.com/"> <!-- Firefox -->
<link rel="prerender" href="http://www.example.com/"> <!-- Chrome -->

前瞻

CSP 3.0的版本已经在路上了,不过,我目测还需要3年(2020年之后),那些不支持CSP 2的浏览器(设备)才会被完全淘汰。而兼容CSP 3/2的浏览器才会逐渐普及。

一些提示

使用CSP策略是应对一些XSS攻击、网页植入广告(无良运营商或者黑客的杰作)、点击劫持等问题的有效办法之一。但使用时一定慎重考量,一方面要做好兼容,另一方面全面了解站点及业务需要,做出合理、灵活的CSP配置。

参考

CSP Reference

发表评论

电子邮件地址不会被公开。 必填项已用*标注