0%

xss之CSP的原理和绕过

CSP的原理和绕过

xss的编码那么复杂,一不小心就会过滤失败,同时不同的触发点还要逐个修复、即使可以统前端过滤,仍存在漏掉的风险。那么有没有一种办法可以禁止用户插入的js代码执行呢?是有的,这就是CSP!

CSP的实现和执行全部由浏览器完成,浏览器来根据你的规则,禁止引入外部的那些链接和插入的js代码的执行,那怎么告诉浏览器我要开启CSP策略呢?

使用方法

1、通过 HTTP 头信息的Content-Security-Policy

1
2
Content-Security-Policy: script-src 'self'; object-src 'none'; 
style-src cdn.example.org third-party.org; child-src https:

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
2
3
4
5
6
Content-Security-Policy
base-uri 'self';
object-src 'self';
script-src 'self' 'unsafe-eval' 'unsafe-inline' 'report-sample' *.xxx.com; 
frame-src 'self' *.xxx.com;
report-uri https://xxx.log.xxx.com

常用的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
2
3
4
5
6
7
8
9
10
11
12
13
14
<! DOCTYPE html >
< html lang="en" >
< head >
    < meta charset="UTF-8" >
    < title > jsonp下XSS注入 < /title>
< /head>
< body >
< script >
    function myCallback(jsonObject) {
        //函数内容
    }
< script src="https://xxx.com?callback=myCallback" ></script>
< /body>
< /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
2
3
4
<embed src="https://not-example.com/flash"></embed>
<object data="https://not-example.com/plugin"></object>
<applet archive="https://not-example.com/java"></applet>
<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==">

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的绕过。

参考


采用署名-非商业性使用-相同方式共享 4.0(CC BY-NC-SA 4.0)许可协议
「分享也是一种学习」