0x00介绍
Content Security Policy (CSP)内容安全策略,是一个附加的安全层,有助于检测并缓解某些类型的攻击,包括跨站脚本(XSS)和数据注入攻击。主要用于防御XSS,CSRF攻击,它通过加载唯一的受信任的CDN的脚本降低脚本注入的风险。一般通过HTTP头和<meta>标签来表达
0x01基本语句
我们常见的CSP的样式为
Content-Security-Policy: default-src 'self'; img-src *;script-src https://cdn.example.com/scripts/; object-src'un'
- default-src 表示资源的来历,self代表匹配同源的来源,这里表示只匹配同站的来源,none代表什么都不匹配
- img-src *;script-src https://cdn.example.com/scripts/; object-src'un' 表示允许本站的任意图片来源和https://cdn.example.com/scripts/下的脚本
其<meta>
的格式为
<meta http-equiv="Content-Security-Policy" content="script-src 'self'">
0x02 CSP测试指令
child-src
该指令控制嵌套上下文,例如<iframe>
和<frame>
导航和上下文的创建:
directive-name = "child-src" directive-value = serialized-source-list
该指令控制将填充框架或工作程序的请求,例如:
Content-Security-Policy: child-src https://example.com/
则如下的代码将返回错误,不匹配child-src源
<iframe src="https://example.org"></iframe> <script> var blockedWorker = new Worker("data:application/javascript,..."); </script>
让我们看一个页面
<?php
header("Content-Security-Policy: child-src https://www.baidu.com/");
?>
<html lang="ch">
<head>
<meta charset="utf-8" />
<title>CSP test</title>
</head>
<body>
<iframe src="https://christa.top" style="width: 100%;height: 800px"></iframe>
<script>
var blockedWorker = new Worker("data:application/javascript,...");
</script>
</body>
</html>
我们可以看到因为CSP的拓展,网页的请求已经被阻止,而访问允许的页面则可以出现响应
同时使用<meta>标签也可以产生同样的效果
<meta http-equiv="Content-Security-Policy" content="script-src 'self'; child-src https://www.baidu.com">
connect-src
该链接限制了其他传输或接收数据的请求,比如API fetch(),[XHR],<a>的ping等函数,同时还控制了WebSocket的连接
如下列的例子都会被限制
<a ping="https://christa.top">...
<script>
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://christa.top/');
xhr.send();
var ws = new WebSocket("wss://christa.top/");
var es = new EventSource("https://christa.top/");
navigator.sendBeacon("https://christa.top/", { ... });
</script>
default-src
该指令的值用作策略的默认源列表,使用default-src 'none';script-src 'self'
,脚本将请求将'self'用作匹配的源列表,其他请求将使用'none'
以下指令
Content-Security-Policy: default-src 'self'等同于
Content-Security-Policy: connect-src 'self'; font-src 'self'; frame-src 'self'; img-src 'self'; manifest-src 'self'; media-src 'self'; prefetch-src 'self'; object-src 'self'; script-src-elem 'self'; script-src-attr 'self'; style-src-elem 'self'; style-src-attr 'self'; worker-src 'self'
因此,当default-src
被设定时,所有的fetch指定将回退到default-src
的值当中,同时该值还没有继承,如果一个script-src
的值被指定了,那么default-src
的指令不再有影响,向如下的头
Content-Security-Policy: default-src 'self'; script-src-elem https://christa.top等同于
Content-Security-Policy: connect-src 'self'; font-src 'self'; frame-src 'self'; img-src 'self'; manifest-src 'self'; media-src 'self'; prefetch-src 'self'; object-src 'self'; script-src-elem https://christa.top; script-src-attr 'self'; style-src-elem 'self'; style-src-attr 'self'; worker-src 'self'
因此,建立这种网站最好使用开始default-src的'none',并建立从设立一个我们允许拿到资源的特定的链接
到这里,我们基本可以猜测到CSP的基本语句,则简化后面的介绍
font-src
Content-Security-Policy: font-src https://christa.top等同于
<style> @font-face { font-family: "Example Font"; src: url("https://christa.top/font"); } body { font-family: "Example Font"; } </style>
frame-src
Content-Security-Policy: frame-src https://christa.top/等同于
<iframe src="https://christa.top/"> </iframe>
img-src
Content-Security-Policy: img-src https://christa.top/等同于
<img src="https://christa.top/img">
manifest-src
Content-Security-Policy: manifest-src https://christa.top/等同于
<link rel="manifest" href="https://christa.top/manifest">
media-src
Content-Security-Policy: media-src https://christa.top/等同于
<audio src="https://christa.top/audio"></audio> <video src="https://christa.top/video"> <track kind="subtitles" src="https://christa.top/subtitles"> </video>
prefetch-src
Content-Security-Policy: prefetch-src https://christa.top/等同于
<link rel="prefetch" src="https://christa.top/"></link> <link rel="prerender" src="https://christa.top/"></link>
object-src
Content-Security-Policy: object-src https://christa.top/等同于
<embed src="https://christa.top/flash"></embed> <object data="https://christa.top/flash"></object> <applet archive="https://christa.top/flash"></applet>
该object-src作用于代表一个所作的任何请求<object>
,<embed>
或apple
元件
script-src
该指令限制了脚本可以被执行的位置,不仅包括<script>元素中的URL,还包括可以触发脚本执行的内联脚本块和XSLT等内容,脚本管理五件事:
- 必须验证CSP是否阻止请求
- 必须验证CSP是否阻止请求的响应
- 内联<script>块必须验证CSP是否阻止元素的内联行为,除非每个策略允许内联脚本或者通过不指定script-src(或default-src)指令的设置
- 以下Javascript执行接收器在"unsafe-eval"上进行控制
1 eval()
2 Function()
3 setTimeout()
4 setInterval()
5.导航的javascript:URL 必须通过script-src的检查
script-src-elm
该指令限制着所有的响应、script请求和script模块,与script-src的区别为
- script-src-elwm 适用于| type| 为"script" 和 “
navigation
” 的链接- script-sec-elem 的值不用于在 'unsafe-eval'中进行接收器的检查
- script-src-elem 不用作
worker-src
指令的后备。该worker-src
检查还依赖script-src
指令。
script-src-attr
该指令适用于事件处理程序,如果存在,它会覆盖script-src
的相关检查指令。
style-src
该指令被用于Document申请请求的位置,它管理着几件事情
- 样式请求必须验证CSP是否阻止请求,包括:1、样式请求源自<link>元素 2、源自 '@import'规则的样式 3、样式表请求源自LinkHTTP响应字段头
- 对样式的请求响应必须验证CSP是否阻止请求响应
- 内联<style>块必须验证CSP是否阻止元素的内联行为。除非每个策略都允许内联样式,否则样式将被阻止,无论是通过不指定
style-src
(或default-src
)指令隐式地,还是通过指定“unsafe-inline
”,none-source或与内联块匹配的hash-source值显示它- 一下CSS算法在unsafe-eval上进行控制:
1. CSS插入规则
2. CSS解析规则
3. 解析CSS声明块
4. 解析一组选择器
style-src-elem 、style-src-attr
与script-src-elem
和style-src-attr
大体上一致,皆在控制CSS响应函数地执行
worker-src
Content-Security-Policy: worker-src https://christa.top/等同于
<script> var blockedWorker = new Worker("data:application/javascript,..."); blockedWorker = new SharedWorker("https://christa.top/"); navigator.serviceWorker.register('https://christa.top/sw.js'); </script>
还有一些基于插件和控制链接地CSP规则就不一一介绍啦。
0X03 CSP绕过
在xxx-src *表除了允许内联函数以外所有的url式请求,很容易造成CSRF漏洞,比如下的CSP
Content-Security-Policy
default-src 'none'; connect-src 'self'; frame-src *; script-src 'self' 'unsafe-inline'
发现由于iframe的内联不同源,故无法通过任何方式get cookie,不存在xss漏洞),但是可以利用这种方式构造CSRF漏洞,但同能看到script-src 'self' 'unsafe-line',可以看到普通的js脚本被拦截
但构造基本的xss语句则能执行
<script>alert(document.cookie);</script>
虽然不能使用外源的XSS,但能够构造cookie给自己的账号留言从而得到cookie,再看一个更加严格的CSP
Content-Security-Policydefault-src 'none'; connect-src 'self'; frame-src 'self'; script-src https://crhista.top/christa.js; style-src 'self' 'unsafe-inline' ; img-src 'self'
将来自本地域的script
禁止了,但如果构造如下payload
<link rel="prefetch" href="httpss://christa.top/christa">
即可以发送请求包向客户端,但如过开发人员都设置了X-Frame-Options:Deny则我们可以在该网站的404站点进行探索,因为并不是所有的404页面都设置了CSP,用NGINX来说的话,我们只需要强制让NGINX返回 400 bad request
,只需要使用/../访问上一级路劲中的资源,可以使用unicode替换。
frame=document.createElement(“iframe”); frame.src=”/%2e%2e%2f”; document.body.appendChild(frame);
这里的另一种可能的方法是传递不正确的unicode路径,如/%或/%%z。又或者传入超过Web服务器可以接受的最大长度的URL,因此使用
frame=document.createElement(“iframe”); frame.src=”/”+”A”.repeat(20000); document.body.appendChild(frame);
更多的绕过姿势慢慢探索吧。。