我在开发人员控制台得到一堆错误:

拒绝计算字符串 拒绝执行内联脚本,因为它违反了以下内容安全策略指示 拒绝加载脚本 拒绝加载样式表

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

具体来说,如何……

...允许多个信息源? ...使用不同的指令? ...使用多个指令? ...处理港口? ...处理不同的协议? ...允许文件://协议? ...使用内联样式,脚本和标签<style>和<script>? ...允许eval () ?

最后:

“自我”到底是什么意思?


当前回答

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

我绞尽脑汁,试图弄清楚为什么我一个接一个地得到CSP错误,但似乎没有任何简洁、清晰的说明它是如何工作的。因此,我在这里尝试简单地解释CSP的一些要点,主要集中在我发现难以解决的问题上。

为了简洁起见,我不会在每个示例中写出完整的标记。相反,我只会显示内容属性,所以一个例子说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. 我如何允许文件协议文件://?

如果你试图这样定义它,它是行不通的。相反,你将允许它使用filesystem参数:

content="default-src filesystem"

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

除非明确允许,否则不能使用内联样式定义、<script>标记内的代码或标记属性(如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”理解为本地主机、本地文件系统或同一主机上的任何东西。这并不意味着任何一种。它意味着源具有与定义内容策略的文件相同的方案(协议)、相同的主机和相同的端口。通过HTTP服务您的站点?没有https,除非你明确定义它。

我在大多数例子中都使用了“self”,因为包含它通常是有意义的,但这绝不是强制性的。如果你不需要,就把它去掉。

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

不。除了明显的安全漏洞之外,这也不能像您期望的那样工作。尽管一些文档声称它允许任何事情,但事实并非如此。它不允许内联或求值,所以真的,真的让你的网站更加脆弱,你可以使用这个:

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

... 但我相信你不会的

进一步阅读:

http://content-security-policy.com

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

其他回答

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;"

注意:这是文件的底部部分。只有后3项是CSP设置。

第一个参数是指令,第二个参数是要列入白名单的源。我添加了谷歌分析和adserver,你可能有。此外,我发现如果您在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/

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

我绞尽脑汁,试图弄清楚为什么我一个接一个地得到CSP错误,但似乎没有任何简洁、清晰的说明它是如何工作的。因此,我在这里尝试简单地解释CSP的一些要点,主要集中在我发现难以解决的问题上。

为了简洁起见,我不会在每个示例中写出完整的标记。相反,我只会显示内容属性,所以一个例子说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. 我如何允许文件协议文件://?

如果你试图这样定义它,它是行不通的。相反,你将允许它使用filesystem参数:

content="default-src filesystem"

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

除非明确允许,否则不能使用内联样式定义、<script>标记内的代码或标记属性(如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”理解为本地主机、本地文件系统或同一主机上的任何东西。这并不意味着任何一种。它意味着源具有与定义内容策略的文件相同的方案(协议)、相同的主机和相同的端口。通过HTTP服务您的站点?没有https,除非你明确定义它。

我在大多数例子中都使用了“self”,因为包含它通常是有意义的,但这绝不是强制性的。如果你不需要,就把它去掉。

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

不。除了明显的安全漏洞之外,这也不能像您期望的那样工作。尽管一些文档声称它允许任何事情,但事实并非如此。它不允许内联或求值,所以真的,真的让你的网站更加脆弱,你可以使用这个:

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

... 但我相信你不会的

进一步阅读:

http://content-security-policy.com

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