CSP的原理和绕过
xss的编码那么复杂,一不小心就会过滤失败,同时不同的触发点还要逐个修复、即使可以统前端过滤,仍存在漏掉的风险。那么有没有一种办法可以禁止用户插入的js代码执行呢?是有的,这就是CSP!
CSP的实现和执行全部由浏览器完成,浏览器来根据你的规则,禁止引入外部的那些链接和插入的js代码的执行,那怎么告诉浏览器我要开启CSP策略呢?
使用方法
1、通过 HTTP 头信息的Content-Security-Policy
1 | Content-Security-Policy: script-src 'self'; object-src 'none'; |
2、通过网页的meta标签。
1 | <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策略字段
我们在网站的响应头重可以看到一般CSP的HTTP Header长这样:
1 | Content-Security-Policy: |
常用的CSP字段表:
指令 | 说明 |
---|---|
default-src | 针对 xxx-src 指令的默认行为 |
script-src | 限制脚本加载白名单 |
base-uri | 指定 <base> 标签的 url 的值 |
child-src | 限制内嵌框架,比如 frame, iframe 的域名白名单 |
connect-src | 限定对外请求域名的白名单 (通过 XHR、WebSockets、EventSource等) |
font-src | 限定字体文件的请求域名白名单 |
form-action | 限定 <form> 标签表单提交的白名单,就是 action 的域名白名单 |
frame-ancestors | 指定可以嵌入当前页面的外部资源。 该指令适用于 <frame> 、<iframe> 、<embed> 和 <applet> 标记。 该指令不能在 <meta> 标记中使用,并且仅适用于非 HTML 资源。 |
frame-src | 等同于 child-src,在第二版废弃过,第三版又恢复 |
img-src | 限定图片加载域名白名单 |
media-src | 限定视频和音频的加载域名白名单 |
object-src | 插件加载白名单,比如 flash |
plugin-types | 限制可以使用的插件格式 |
report-uri | 指定当违反内容安全策略时浏览器将发送报告的 URL。 此指令不能在 标记中使用。 下面有 demo 演示 |
style-src | 样式表加载白名单 |
upgrade-insecure-requests | 自动将网页上所有加载外部资源的 HTTP 链接换成 HTTPS 协议 |
worker-src | 限制 worker 加载白名单(包含 shared worker,service worker), 第三版才有, 支持有限 |
对于不同的src分别设置有时候是繁杂的。可以通过default-src统一设置默认。当default-src设置时,任何xxx-src如果没有设置,即为default-src的策略,如果设置则覆盖default-src的策略。
CSP特殊设置字段
unsafe-inline 含义
unsafe-inline允许内联的js和css的执行,比如on事件、javascript伪协议script标签内代码等。如果不声明此字段,很多网站的功能可能会异常。但是这并不是CSP的缺陷,而是开发编码的问题,如果可以做到统一不使用内联js,比如编排好使用的js文件,不使用内联函数,关闭unsafe-inline即可防止绝大多数的xss。
当然也有另一种方法可以在不实用unsafe-inline的情况下执行js代码,比如:
1 | <script>alert('Hello, world.');</script> |
这个代码的哈希值计算结果放在 CSP 里面:
Content-Security-Policy: script-src ‘sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng=’
但是即使禁用了unsafe-inline script-src还有另一个攻击面: data:src
当date可用时也会造成xss的攻击
1 | <script src="data:text/javascript,evil()"></script> |
unsafe-eval含义
unsafe-eval允许将字符串重新转为可执行代码,比较高风险,如无必要,也是禁止开放。
object-src
如果没有default-src设置的话,object-src必须设置,因为Flash 里面可以执行外部脚本。会导致各种安全问题。
JSONP
必须特别注意 JSONP 的回调函数。因为再多次测试中发现,jsonp的回调函数一般是可控的,这种同域名下的可控回调会导致CSP策略的失效。比如你限制了必需是网站子域名,正好子域名中有一个jsonp回调函数可控,那么就有了加载任意js的资源点。
一旦myCallback参数可控且在返回中,那么返回的js代码就可控了。
1 | <! DOCTYPE html > |
CSP的错误配置和绕过
推荐一个分析CSP策略缺陷的在线工具:https://csp-evaluator.withgoogle.com/
为了正常功能使用unsafe-inline
如下面的策略使用了unsafe-inline就可以争产的xss注入了
1 | Content-Security-Policy: script-src https://sina.com https://baidu.com 'unsafe-inline' child-src 'none'; report-uri /Report-parsing-url; |
忘记配置object-src
1 | Content-Security-Policy: script-src https://sina.com https://baidu.com 'unsafe-inline'; report-uri /Report-parsing-url; |
上面的代码没有配置object-src属性,可能会导致flash相关的安全问题,以下几种标签都可以加载flash。
1 | <embed src="https://not-example.com/flash"></embed> |
jsonp绕过CSP
1 | Content-Security-Policy:script-src ‘self’ accounts.google.com/random/ website.with.redirect.com; object-src ‘none’; report-uri /Report-parsing-url; |
如果白名单内的域名存在jsonp回调函数可操纵的漏洞,就会造成CSP的绕过。