南琴浪博客

Content Security Policy 概述

10/15/2017

内容安全策略(Content Security Policy),简称 CSP,顾名思义了,是一种针对内容安全方面的保护策略。作用是用来定义页面中哪些资源可以加载,以减少 XSS 的发生

Chrome 25+ 和 Firefox 23+ 已经加入对 CSP 的支持,其它浏览器的支持起步较晚,不过现在的浏览器已经较普遍的支持了。浏览器的具体支持情况可以参看 CanIUse

什么是 XSS 攻击

跨站脚本(英语:Cross-site scripting,通常简称为:XSS)是一种网站应用程序的安全漏洞攻击,是代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。这类攻击通常包含了 HTML 以及用户端脚本语言。

跨域脚本攻击(XSS 攻击)通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是 JavaScript,但实际上也可以包括 Java,VBScript,ActiveX,Flash 甚至是普通的 HTML。攻击成功后,攻击者可能得到更高的权限(如执行一些操作)、私密网页、会话和 cookie 等各种内容。

为了防止它,要采取很多编程对策,成本较高。很多人发出呼声,能不能让浏览器自己禁止外部注入恶意脚本呢?这时,CSP 应运而生。

什么是 CSP

上文已提到,CSP 定义了页面中哪些资源可以加载。

所以 CSP 的实质就是白名单,Web 端明确地告诉客户端,只有哪些外部资源可以加载可以执行,相当于提供一份白名单,“我的规则里没提到的全部拜拜,不给进来”。

因此 CSP 大大增强了网页的安全性。即使攻击者发现可趁之机,也没法注入脚本。

CSP 的两种启用方式

两种方法启用 CSP :

一种是使用网页的 <meta> 标签

<meta http-equiv="Content-Security-Policy" content="default-src ${value}; script-src ${value}; style-src ${value}; img-src ${value}; font-src ${value}; media-src ${value}; object-src ${value}; connect-src ${value}; child-src ${value}; sandbox ${value}; report-uri ${value}">

一种是使用 HTTP 响应头

Content-Security-Policy: "default-src ${value}; script-src ${value}; style-src ${value}; img-src ${value}; font-src ${value}; media-src ${value}; object-src ${value}; connect-src ${value}; child-src ${value}; sandbox ${value}; report-uri ${value}"

以上,例如 script-src参数项${value}参数值。作为白名单的 CSP 机制,参数项都是可选项

CSP 的规则定义

一、参数项 的定义见下表:

参数项定义
default-src所有类型资源的默认加载策略。若某类型资源有独立定义加载策略就跟随该独立定义;反之跟随 default-src 的定义值
script-srcJavaScript 的加载策略
style-src样式的加载策略
img-src图片的加载策略
font-srcWebFont 的加载策略
media-src<audio> <video> 等标签引入的 HTML 多媒体的加载策略
object-src<object> <embed> <applet> 等标签引入的 flash 等插件的加载策略
connect-srcAjax、WebSocket 等请求的加载策略。若策略的值为不允许,浏览器会模拟一个状态 400 的响应
child-srcframe 的加载策略
sandbox对请求的资源启用 sandbox。参数值可参考 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox
report-uri告诉浏览器,若请求的资源不被 CSP 策略允许时,往哪个地址提交日志信息

二、参数值的定义见下表:

参数值定义
(空)允许任何内容
‘none’不允许任何内容
‘self’允许来自相同来源(相同的域名、端口、协议)的内容
example.org允许加载指定域名的资源
*.example.org允许加载 example.org 任何子域名的资源
https://example.org允许加载指定域名的 HTTPS 协议的资源
https:允许加载 HTTPS 资源
data:允许 data: 协议
‘unsafe-inline’仅用于 script-src 和 style-src 的值。允许加载 inline 资源(例如常见的 onclick、inline js、style 属性、inline css 等
‘unsafe-eval’仅用于 script-src 的值。允许加载动态 js 代码,例如 eval、setTimeout、new Function 等

以上,CSP 可控制的项目非常丰富。

如果不指定 ‘unsafe-inline’ ,页面上所有 inline 样式都不会执行;不指定 ‘unsafe-eval’,页面上所有 eval 等动态代码都不会执行。

在限制页面资源加载后,被 XSS 的可能性小了不少。

当然,仅仅靠 CSP 来防范 XSS 显然远远不够。但它成本低,用起来方便啊。

CSP 在 Nginx 中的启用

上文已提到,CSP 可通过 HTTP 响应头 的方式部署。

若要在 Nginx 中配置:

add_header  Content-Security-Policy  "default-src ${value}; script-src ${value}; style-src ${value}; img-src ${value}; font-src ${value}; media-src ${value}; object-src ${value}; connect-src ${value}; child-src ${value}; sandbox ${value}; report-uri ${value}";

举个例子,本站的 CSP 是这样的:

add_header  Content-Security-Policy  "default-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://www.w3.org https://avatars0.githubusercontent.com; font-src 'none'; media-src 'none'; object-src 'none'; connect-src 'self' https://github.com https://api.github.com; child-src 'none'" always;

现代 web 浏览器已提供许多安全性响应头支持,更多详细可阅读我的另一篇帖子 那些站点安全相关的 HTTP 响应头