【问题标题】:How does Content Security Policy (CSP) work?内容安全策略 (CSP) 如何工作?
【发布时间】:2015-07-28 14:38:15
【问题描述】:

我在开发者控制台中遇到了一堆错误:

拒绝评估字符串

拒绝执行内联脚本,因为它违反了以下内容安全策略指令

拒绝加载脚本

拒绝加载样式表

这是怎么回事?内容安全策略 (CSP) 如何工作?如何使用Content-Security-Policy HTTP 标头?

具体来说,如何...

  1. ...允许多个来源?
  2. ...使用不同的指令?
  3. ...使用多个指令?
  4. ...处理端口?
  5. ...处理不同的协议?
  6. ...允许file:// 协议?
  7. ...使用内联样式、脚本和标签<style><script>?
  8. ...允许eval()?

最后:

  1. 'self' 到底是什么意思?

【问题讨论】:

标签: javascript html security http-headers content-security-policy


【解决方案1】:

Content-Security-Policy 元标记允许您定义可以从哪里加载资源,防止浏览器从任何其他位置加载数据,从而降低 XSS 攻击的风险。这使得攻击者更难将恶意代码注入您的网站。

我用头撞了一堵砖墙,试图弄清楚为什么我一个接一个地遇到 CSP 错误,但似乎没有任何简明、明确的说明来说明它是如何工作的。因此,这是我试图简要解释 CSP 一些点的尝试,主要集中在我发现难以解决的问题上。

为简洁起见,我不会在每个示例中写出完整的标签。相反,我将只显示content 属性,因此content="default-src 'self'" 的示例意味着:

<meta http-equiv="Content-Security-Policy" content="default-src 'self'">

1.如何允许多个来源?

您可以简单地在指令之后以空格分隔的列表形式列出您的来源:

content="default-src 'self' https://example.com/js/"

请注意,除了特殊参数(如'self')之外,参数周围没有引号。此外,指令后没有冒号 (:)。只是指令,然后是空格分隔的参数列表。

指定参数以下的所有内容都是隐式允许的。这意味着在上面的示例中,这些将是有效的来源:

https://example.com/js/file.js
https://example.com/js/subdir/anotherfile.js

但是,这些是无效的:

http://example.com/js/file.js
^^^^ wrong protocol

https://example.com/file.js
                   ^^ above the specified path

2。如何使用不同的指令?他们各自做什么?

最常见的指令是:

  • default-src加载javascript、图片、CSS、字体、AJAX请求等的默认策略
  • script-src 定义了 javascript 文件的有效来源
  • style-src 定义 css 文件的有效来源
  • img-src 定义图片的有效来源
  • connect-src 定义 XMLHttpRequest (AJAX)、WebSockets 或 EventSource 的有效目标。如果尝试连接到此处不允许的主机,浏览器将模拟400 错误

还有其他的,但这些是您最可能需要的。

3.如何使用多个指令?

您可以在一个元标记中定义所有指令,方法是用分号 (;) 终止它们:

content="default-src 'self' https://example.com/js/; style-src 'self'"

4.如何处理端口?

除了默认端口之外的所有内容都需要通过在允许的域后添加端口号或星号来明确允许:

content="default-src 'self' https://ajax.googleapis.com http://example.com:123/free/stuff/"

以上将导致:

https://ajax.googleapis.com:123
                           ^^^^ Not ok, wrong port

https://ajax.googleapis.com - OK

http://example.com/free/stuff/file.js
                 ^^ Not ok, only the port 123 is allowed

http://example.com:123/free/stuff/file.js - OK

正如我所提到的,您还可以使用星号来明确允许所有端口:

content="default-src example.com:*"

5.如何处理不同的协议?

默认情况下,只允许使用标准协议。例如,要允许 WebSockets ws:// 你必须明确地允许它:

content="default-src 'self'; connect-src ws:; style-src 'self'"
                                         ^^^ web Sockets are now allowed on all domains and ports.

6.如何允许文件协议file://

如果您尝试这样定义它,它将无法正常工作。相反,您可以使用 filesystem 参数来允许它:

content="default-src filesystem"

7.如何使用内联脚本和样式定义?

除非明确允许,否则您不能使用内联样式定义、&lt;script&gt; 标记内或 onclick 等标记属性中的代码。你允许他们这样:

content="script-src 'unsafe-inline'; style-src 'unsafe-inline'"

您还必须明确允许内联、base64 编码的图像:

content="img-src data:"

8.我怎样才能允许eval()

我相信很多人会说你不知道,因为“eval 是邪恶的”并且最有可能导致即将到来的世界末日。那些人就错了。当然,您绝对可以使用 eval 在您网站的安全性中打出重大漏洞,但它具有完全有效的用例。你只需要聪明地使用它。你允许这样:

content="script-src 'unsafe-eval'"

9. 'self' 到底是什么意思?

您可能会认为'self' 表示本地主机、本地文件系统或同一主机上的任何内容。这并不意味着其中任何一个。这意味着源与定义内容策略的文件具有相同的方案(协议)、相同的主机和相同的端口。通过 HTTP 为您的站点提供服务?除非你明确定义它,否则没有 https 给你。

我在大多数示例中都使用了'self',因为包含它通常是有意义的,但这绝不是强制性的。如果你不需要它,请忽略它。

但请稍等!我不能只使用content="default-src *" 并完成它吗?

没有。除了明显的安全漏洞之外,这也不会像您期望的那样工作。尽管some docs 声称它允许任何事情,但事实并非如此。它不允许内联或评估,因此要真正让您的网站更加容易受到攻击,您可以使用:

content="default-src * 'unsafe-inline' 'unsafe-eval'"

...但我相信你不会。

进一步阅读:

http://content-security-policy.com

http://en.wikipedia.org/wiki/Content_Security_Policy

【讨论】:

  • 很棒的帖子。一件事:当指定多个指令时会发生什么并不明显;示例 3 中的 style-src 设置是否优先于 default-src?等等……
  • 所以,要允许 everything everything Everything,内容将是 default-src *; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'; img-src * data: 'unsafe-inline'; connect-src * 'unsafe-inline'; frame-src *;
  • 重要的是要知道content="default-src * 'unsafe-inline' 'unsafe-eval'" 是使某些 Angular 应用程序正常工作所必需的。
  • @Mahesh 那个“博客”充满了从 SO 复制的帖子。似乎不太可能有这么多 SO 用户从不知名的博主那里复制内容——我知道我没有。
  • 关于connect-src 和路径的简短说明:如果要包含整个子路径,则必须使用斜杠。例如:如果源是http://foo.com/files,文件http://foo.com/files/bar.txt将被阻止,但当它是http://foo.com/files/时提供服务
【解决方案2】:

Apache 2 mod_headers

您也可以启用 Apache 2 mod_headers。在Fedora 上,它已默认启用。如果您使用 Ubuntu/Debian,请像这样启用它:

# First enable headers module for Apache 2,
# and then restart the Apache2 service
a2enmod headers
apache2 -k graceful

在 Ubuntu/Debian 上,您可以在文件中配置标头 /etc/apache2/conf-enabled/security.conf

#
# Setting this header will prevent MSIE from interpreting files as something
# else than declared by the content type in the HTTP headers.
# Requires mod_headers to be enabled.
#
#Header set X-Content-Type-Options: "nosniff"

#
# Setting this header will prevent other sites from embedding pages from this
# site as frames. This defends against clickjacking attacks.
# Requires mod_headers to be enabled.
#
Header always set X-Frame-Options: "sameorigin"
Header always set X-Content-Type-Options nosniff
Header always set X-XSS-Protection "1; mode=block"
Header always set X-Permitted-Cross-Domain-Policies "master-only"
Header always set Cache-Control "no-cache, no-store, must-revalidate"
Header always set Pragma "no-cache"
Header always set Expires "-1"
Header always set Content-Security-Policy: "default-src 'none';"
Header always set Content-Security-Policy: "script-src 'self' www.google-analytics.com adserver.example.com www.example.com;"
Header always set Content-Security-Policy: "style-src 'self' www.example.com;"

注意:这是文件的底部。只有最后三个条目是 CSP 设置。

第一个参数是指令,第二个是要列入白名单的来源。我添加了谷歌分析和广告服务器,你可能有。此外,我发现如果您在 Apache 2 中配置了别名,例如 www.example.com 和 example.com,您也应该将它们添加到白名单中。

内联代码被认为是有害的,你应该避免它。将所有 JavaScript 代码和 CSS 复制到单独的文件中,并将它们添加到白名单中。

当您使用它时,您可以查看其他标头设置并安装 mod_security

进一步阅读:

https://developers.google.com/web/fundamentals/security/csp/

https://www.w3.org/TR/CSP/

【讨论】:

  • 我能够将这些相同的指令添加到我的 .htaccess 文件中,因为我无法在我的共享主机上编辑 Apache 配置。我在report-uri.io/home/tools找到了调整这些设置的优秀工具。
  • 有没有办法用tomcat 7解决这个问题。我试过添加过滤器,但没有用。
猜你喜欢
  • 2021-12-26
  • 2013-10-09
  • 2023-01-07
  • 2016-03-25
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
  • 2019-08-10
  • 1970-01-01
相关资源
最近更新 更多