内容安全策略(Content Security Policy)是一个额外的安全层,用于检测并削弱某些特定类型的攻击,包括跨站脚本(XSS)和数据库注入攻击(SQL注入)等。无论是数据盗取、网站内容污染还是散发恶意软件,这些攻击都是主要的手段。
内容安全策略CSP取决于浏览器的支持,是完全向后兼容的。
不支持CSP的浏览器也能与实现了CSP的服务器正常合作,反之亦然:不支持 CSP 的浏览器只会忽略它,如常运行,默认为网页内容使用标准的同源策略。如果网站不提供 CSP 头部,浏览器也使用标准的同源策略。
要使用内容安全策略CSP,可以在服务端的Response Headers配置 Content-Security-Policy 头部,旧版本的字段会是X-Content-Security-Policy,设置其中一个即可。
除此之外,也可以通过HTML中的meta标签来配置CSP:
<meta http-equiv="Content-Security-Policy" content="default-src 'self';" />
这样即指定了CSP,上述meta语句指定了可以加载内容的域为本服务器的地址。
威胁
跨站脚本攻击Cross Site Script(XSS)
CSP 的主要目标是减少和报告 XSS 攻击 ,XSS 攻击利用了浏览器对于从服务器所获取的内容的信任。恶意脚本在受害者的浏览器中得以运行,因为浏览器信任其内容来源,即使有的时候这些脚本并非来自于它本该来的地方。
CSP通过指定有效域——即浏览器认可的可执行脚本的有效来源——使服务器管理者有能力减少或消除XSS攻击所依赖的载体。一个CSP兼容的浏览器将会仅执行从白名单域获取到的脚本文件,忽略所有的其他脚本 (包括内联脚本和HTML的事件处理属性)。
作为一种终极防护形式,始终不允许执行脚本的站点可以选择全面禁止脚本执行。
数据包嗅探攻击
除限制可以加载内容的域,服务器还可指明哪种协议允许使用;比如 (从理想化的安全角度来说),服务器可指定所有内容必须通过HTTPS加载。一个完整的数据安全传输策略不仅强制使用HTTPS进行数据传输,也为所有的cookie标记安全标识 cookies with the security flag 并且提供自动的重定向使得HTTP页面导向HTTPS版本。网站也可以使用 Security-Transport-Security HTTP头部确保连接它的浏览器只使用加密通道 。
使用CSP内容安全策略
要使用CSP,涉及到 Content-Security-Policy 的配置。
对HTTP头部配置相应的值,以控制用户代理(浏览器等)可以为该页面获取哪些资源。
比如一个可以上传文件和显示图片页面,应该允许图片来自任何地方,但限制表单的action属性只可以赋值为指定的端点。一个经过恰当设计的内容安全策略应该可以有效的保护页面免受跨站脚本(XSS)攻击。
制定策略
制定策略,其实就是对 Content-Security-Policy 的值进行配置,格式为:
Content-Security-Policy: $_policy;
$_policy 就是一个包含了各种描述CSP内容安全策略指令的字符串。
描述策略
描述策略,即实现$_policy。
default-src
对于描述策略,首先应制定 default-src 的值。
default-src 指令可以为其他CSP拉取指令提供默认值,对于以下具体的拉取指令,如果没有给定策略,则会采取 default-src 的策略值。“具体的拉取指令”,有如下指令:
child-src
定义web-workers和嵌入的浏览器内容(例如通过<frame>或<iframe>嵌入的页面)的支持的源。
- connect-src
这个指令用于控制允许通过脚本接口加载的链接地址。其中受到影响的API如下:
a标签的ping属性FetchXMLHttpRequestWebSocketEventSource
- font-src
这个指令定义了@font-face加载字体的有效源规则。
- frame-src
定义<frame>和<iframe>的有效源规则。
- img-src
图片。
- manifest-src
- media-src
定义<audio>和<video>标签的有效源规则。
- object-src
定义<object>、<embed>、<applet>的有效源规则。
- script-src
定义脚本,包括但不限于<script>标签、DOM点击事件的内联脚本的有效源规则。
- style-src
- worker-src
定义Worker ,SharedWorker , ServiceWorker脚本的有效源规则。
配置语法
Content-Security-Policy: default-src <source> <source>;
<source> 可以是以下之一:
<host-source>
以域名或者 IP 地址表示的主机名,外加可选的 URL 协议名以及端口号。站点地址中可能会包含一个可选的前置通配符(星号 ' '),同时也可以将通配符(也是' ')应用于端口号,表示在这个源中可以使用任意合法的端口号。 举例说明:
http://*.example.com:匹配从使用 http: 的 example.com 的任意子域的资源加载。mail.example.com:443:匹配对 mail.example.com 上的 443 端口号的访问。https://store.example.com: 匹配对使用了 https: 的 store.example.com 的访问。
<scheme-source>
协议名如'http:' 或者 'https:'。必须带有冒号,不要有单引号。
Content-Security-Policy: default-src "https:";
'self'
指向与要保护的文件所在的源,包括相同的 URL scheme 与端口号。必须有单引号。
unsafe-inline
允许使用内联资源。
unsafe-eval
允许使用 eval() 以及相似的函数来从字符串创建代码。必须有单引号。
'none'
不允许任何内容。 必须有单引号。
'nonce-<base64值>'
特定使用一次性加密内联脚本的白名单。服务器必须在每一次传输政策时生成唯一的一次性值。否则将存在绕过资源政策的可能。
<hash-source>
使用 sha256、sha384 或 sha512 编码过的内联脚本或样式。其由用短划线分隔的两部分组成: 用于创建哈希的加密算法, 以及脚本或样式base64编码的哈希值。当生成哈希值的时候,不要包含 <script> 或 <style> 标签,同时注意字母大小写与空格——包括首尾空格——都是会影响生成的结果的。
'strict-dynamic'
指定对于含有标记脚本(通过附加一个随机数或散列)的信任,应该传播到由该脚本加载的所有脚本。与此同时,任何白名单以及源表达式例如 'self' 或者 'unsafe-inline' 都会被忽略。
示例
Content-Security-Policy: connect-src 'self';
font-src 'self';
frame-src 'self';
img-src 'self';
manifest-src 'self';
media-src 'self';
object-src 'self';
script-src https://example.com;
style-src 'self';
worker-src 'self';