CSP简介和案例分析
在互联网中,网页的面临安全性问题很多,虽然HTTPS能解决大多数的问题,但HTTPS在国内环境中存在严重的劫持问题,所以在某些网络情况下还在使用HTTP协议,也就面临着:
- JS劫持;
- 广告注入;
- 跨站脚本攻击(XSS);
等等诸多问题。
CSP简介
Content Security Policy简称CSP,用来解决跨站脚本攻击及其类似安全问题的一组安全策略,可用来初步解决上面的问题。
CSP发展很快,自2012年第一版诞生依赖,至今第二版已经进入W3C的推荐版本,第三版也处于工作草案阶段。W3C建议浏览器基于第二版规范实现(浏览器兼容性),CSP在第二版中的官方定义如下:
This document defines a policy language used to declare a set of content restrictions for a web resource, and a mechanism for transmitting the policy from a server to a client where the policy is enforced.
CSP中指令名的含义
| 指令名 | 规范版本 | 含义 | 
|---|---|---|
| default-src | Level 1 | 加载JavaScript、CSS、图片、字体、AJAX、Frame和HTML5媒体等资源的默认策略 | 
| script-src | Level 1 | 定义合法的JavaScript源 | 
| style-src | Level 1 | 定义合法的CSS样式表源 | 
| img-src | Level 1 | 定义合法的图片源 | 
| font-src | Level 1 | 定义合法的字体源 | 
| connect-src | Level 1 | 适用于XMLHttpRequest (AJAX), WebSocket或EventSource。当不合法的请求发出时,浏览器会模拟一个404回复 | 
| media-src | Level 1 | 定义合法的媒体源,例如HTML5中的 <audio>,<video>元素 | 
| object-src | Level 1 | 定义合法的插件源,例如 <object>,<embed>或<applet> | 
| frame-src | Deprecated | 定义合法的框架源。使用 child-src替代其更合适 | 
| sandbox | Level 1 | 针对请求的资源使用沙箱,类似于 iframe的sandbox属性。沙箱适用于同源策略,禁用弹窗,被阻止的插件和脚本。保持空属性值以保留所有限制,也可以添加后面的值:allow-forms allow-same-origin allow-scripts allow-popups,allow-modals,allow-orientation-lock,allow-pointer-lock,allow-presentation,allow-popups-to-escape-sandbox,和allow-top-navigation | 
| report-uri | Level 1 | 指定策略应用失败的URI,也可以在 Content-Security-PolicyHTTP头后添加-Report-Only指示浏览器仅报告错误,但不阻止内容的加载 | 
| child-src | Level 2 | 定义web worker或者frame的合法源,例如 <frame>和<iframe>等 | 
| form-action | Level 2 | 定义 <form>的action属性使用的合法源 | 
| frame-ancestors | Level 2 | 定义 <frame><iframe><object><embed><applet>等元素使用的合法源。将其设置为none大致等于X-Frame-Options: DENY | 
| plugin-types | Level 2 | 定义通过<object>和<embed>元素调用的资源类型。例如加载 <applet>需要设置application/x-java-applet | 
CSP中指令值的含义
上述的任何CSP指令均可以赋一下值,有效值类型的列表如下:
| 指令值 | 示例 | 含义 | 
|---|---|---|
| * | img-src * | 通配符,允许任何URL接收 data:blob:filesystem:schemes | 
| ‘none’ | object-src 'none' | 拒绝加载任何资源 | 
| ‘self’ | script-src 'self' | 允许加载同源资源(相同的协议、域名、端口) | 
| data: | img-src 'self' data: | 允许加载data编码的资源(例如图片的Base64编码) | 
| domain.example.com | img-src domain.example.com | 允许从指定的域名加载资源 | 
| *.example.com | img-src *.example.com | 允许从example.com下的任何子域名加载资源 | 
| https://cdn.com | img-src https://cdn.com | 允许加载https://cdn.com下的资源 | 
| https: | img-src https: | 仅允许加载https协议的资源 | 
| ‘unsafe-inline’ | script-src 'unsafe-inline' | 允许使用内联元素,比如style属性,onclick,或script标签 | 
| ‘unsafe-eval’ | script-src 'unsafe-eval' | 允许不安全的动态脚本执行,比如JavaScript的 eval() | 
使用方式
CSP主要有两种使用方式HTTP HEADER和标签两种方式:
// header
Content-Security-Policy: default-src https:
// meta tag
<meta http-equiv="Content-Security-Policy" content="default-src https:">
案例分析
页面在最终用户面前显示时,页面内容可能在中间的任何一个网络环节被篡改或者拦截,因此网页中的各种资源类型都需要做一定的约束。需要约束的主要资源列表如下:
- JS文件,JS文件是浏览器中最具有表现力的文件,可以修改浏览器中渲染页面的任何元素;
- CSS文件,CSS文件决定了浏览器外观,CSS文件的篡改可以让浏览器中的渲染的页面样子完全改变;
- HTML文件,HTML文件可能被追加内容(最常见),当然也可以删改,甚至可能完全拦截;
- iframe元素,iframe元素类似HTML页面中的一个沙盒,像是一个独立的世界,所以要对iframe元素的内容呈现进行约束;
- 等等
同时行内脚本的解析要暂时放开。
根据以上条件,最后的策略值如下:
// 使用时需要去掉换行和注释
Content-Security-Policy:
    // 默认情况,严格安全策略
    default-src 'none'; 
    // 限制jsonp,外联脚本,内联脚本和行内事件绑定,以及可能的eval
    script-src *.domain.com *.domainimg.com 'unsafe-inline' 'unsafe-eval'; 
    // 限制外联样式和内联样式
    style-src *.domainimg.com 'unsafe-inline'; 
    // ajax限制同源限制
    connect-src 'self'; 
    // 限制图片,支持HTTP和HTTPS,如备注解释
    img-src http://*.domainimg.com https://*.domainimg.com; 
    // 限制字体文件
    font-src *.domain.com *.domainimg.com; 
    // 限制iframe,这行代码虽然标注废弃,但在旧版本浏览器中适用
    frame-src none; 
    // 限制iframe
    child-src: none; 
    // 限制iframe
    frame-ancestors: none;
注意
注意在HTTPS页面中启用CSP之后,会禁用HTTP的请求,类似添加了
block-all-mixed-content指令的效果,而且block-all-mixed-content不能关闭,解决这个问题的方法可以是: 在需要http的资源类型中,如上img-src中明确写明http和https两种模式。