内容安全策略 (CSP) 如何运作?
How does Content Security Policy (CSP) work?
我在开发者控制台中遇到了一堆错误:
Refused to evaluate a string
Refused to execute inline script because it violates the following Content Security Policy directive
Refused to load the script
Refused to load the stylesheet
这是怎么回事?内容安全策略 (CSP) 如何运作?如何使用 Content-Security-Policy
HTTP header?
具体来说,如何...
- ...允许多个来源?
- ...使用不同的指令?
- ...使用多个指令?
- ...处理端口?
- ...处理不同的协议?
- ...允许
file://
协议?
- ...使用内联样式、脚本和标签
<style>
和 <script>
?
- ...允许
eval()
?
最后:
'self'
到底是什么意思?
Content-Security-Policy
元标记允许您定义从何处加载资源,从而防止浏览器从任何其他位置加载数据,从而降低 XSS 攻击的风险。这使得攻击者更难将恶意代码注入您的站点。
我把头撞在一堵砖墙上试图弄清楚为什么我会一个接一个地收到 CSP 错误,但似乎没有关于它如何工作的任何简明、清晰的说明。所以这是我尝试简要解释 CSP 的一些 点,主要集中在我发现难以解决的事情上。
为简洁起见,我不会在每个示例中写下完整的标签。相反,我将只显示 content
属性,因此显示 content="default-src 'self'"
的示例意味着:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
1.如何允许多个来源?
您可以在指令后以 space 分隔列表的形式简单地列出您的来源:
content="default-src 'self' https://example.com/js/"
请注意,除 特殊 参数外,参数周围没有引号,例如 'self'
。此外,指令后没有冒号 (:
)。只是指令,然后是 space 分隔的参数列表。
低于指定参数的所有内容都是隐式允许的。这意味着在上面的示例中,这些将是有效的来源:
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.如何使用内联脚本和样式定义?
除非明确允许,否则您不能使用内联样式定义、<script>
标签内的代码或 onclick
等标签属性中的代码。你允许他们这样:
content="script-src 'unsafe-inline'; style-src 'unsafe-inline'"
您还必须明确允许内联、base64 编码的图像:
content="img-src data:"
8.我怎样才能允许 eval()
?
我敢肯定很多人会说你不知道,因为 'eval is evil' 这也是世界末日即将来临的最可能原因。那些人会错的。当然,您绝对可以使用 eval 对站点的安全性造成重大漏洞,但它有完全有效的用例。你只需要聪明地使用它。你允许这样:
content="script-src 'unsafe-eval'"
9. 'self'
到底是什么意思?
您可能认为 'self'
表示本地主机、本地文件系统或同一主机上的任何内容。这并不意味着任何这些。这意味着来源与定义内容策略的文件具有相同的方案(协议)、相同的主机和相同的端口。通过 HTTP 为您的站点提供服务?除非您明确定义,否则没有 https 供您使用。
我在大多数示例中都使用了 'self'
,因为包含它通常是有意义的,但这绝不是强制性的。如果你不需要它就把它留下。
但是等一下!我不能只用 content="default-src *"
就完事了吗?
没有。除了明显的安全漏洞外,这也不会像您预期的那样工作。尽管 some docs 声称它允许任何事情,但事实并非如此。它不允许内联或评估,所以要真正让您的网站更加脆弱,您可以使用:
content="default-src * 'unsafe-inline' 'unsafe-eval'"
...但我相信你不会。
进一步阅读:
阿帕奇 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 上,您可以在文件中配置 headers
/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 设置。
第一个参数是指令,第二个是要成为的来源white-listed。我添加了 Google 分析和广告服务器,您可能有。此外,我发现如果您在 Apache 2 中配置了别名,例如 www.example.com 和 example.com,您也应该将它们添加到 white-list。
内联代码被认为是有害的,您应该避免使用它。将所有JavaScript代码和CSS复制到单独的文件中,并将它们添加到white-list.
当你在看的时候,你可以看看其他 header 设置并安装 mod_security
进一步阅读:
https://developers.google.com/web/fundamentals/security/csp/
我在开发者控制台中遇到了一堆错误:
Refused to evaluate a string
Refused to execute inline script because it violates the following Content Security Policy directive
Refused to load the script
Refused to load the stylesheet
这是怎么回事?内容安全策略 (CSP) 如何运作?如何使用 Content-Security-Policy
HTTP header?
具体来说,如何...
- ...允许多个来源?
- ...使用不同的指令?
- ...使用多个指令?
- ...处理端口?
- ...处理不同的协议?
- ...允许
file://
协议? - ...使用内联样式、脚本和标签
<style>
和<script>
? - ...允许
eval()
?
最后:
'self'
到底是什么意思?
Content-Security-Policy
元标记允许您定义从何处加载资源,从而防止浏览器从任何其他位置加载数据,从而降低 XSS 攻击的风险。这使得攻击者更难将恶意代码注入您的站点。
我把头撞在一堵砖墙上试图弄清楚为什么我会一个接一个地收到 CSP 错误,但似乎没有关于它如何工作的任何简明、清晰的说明。所以这是我尝试简要解释 CSP 的一些 点,主要集中在我发现难以解决的事情上。
为简洁起见,我不会在每个示例中写下完整的标签。相反,我将只显示 content
属性,因此显示 content="default-src 'self'"
的示例意味着:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
1.如何允许多个来源?
您可以在指令后以 space 分隔列表的形式简单地列出您的来源:
content="default-src 'self' https://example.com/js/"
请注意,除 特殊 参数外,参数周围没有引号,例如 'self'
。此外,指令后没有冒号 (:
)。只是指令,然后是 space 分隔的参数列表。
低于指定参数的所有内容都是隐式允许的。这意味着在上面的示例中,这些将是有效的来源:
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.如何使用内联脚本和样式定义?
除非明确允许,否则您不能使用内联样式定义、<script>
标签内的代码或 onclick
等标签属性中的代码。你允许他们这样:
content="script-src 'unsafe-inline'; style-src 'unsafe-inline'"
您还必须明确允许内联、base64 编码的图像:
content="img-src data:"
8.我怎样才能允许 eval()
?
我敢肯定很多人会说你不知道,因为 'eval is evil' 这也是世界末日即将来临的最可能原因。那些人会错的。当然,您绝对可以使用 eval 对站点的安全性造成重大漏洞,但它有完全有效的用例。你只需要聪明地使用它。你允许这样:
content="script-src 'unsafe-eval'"
9. 'self'
到底是什么意思?
您可能认为 'self'
表示本地主机、本地文件系统或同一主机上的任何内容。这并不意味着任何这些。这意味着来源与定义内容策略的文件具有相同的方案(协议)、相同的主机和相同的端口。通过 HTTP 为您的站点提供服务?除非您明确定义,否则没有 https 供您使用。
我在大多数示例中都使用了 'self'
,因为包含它通常是有意义的,但这绝不是强制性的。如果你不需要它就把它留下。
但是等一下!我不能只用 content="default-src *"
就完事了吗?
没有。除了明显的安全漏洞外,这也不会像您预期的那样工作。尽管 some docs 声称它允许任何事情,但事实并非如此。它不允许内联或评估,所以要真正让您的网站更加脆弱,您可以使用:
content="default-src * 'unsafe-inline' 'unsafe-eval'"
...但我相信你不会。
进一步阅读:
阿帕奇 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 上,您可以在文件中配置 headers
/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 设置。
第一个参数是指令,第二个是要成为的来源white-listed。我添加了 Google 分析和广告服务器,您可能有。此外,我发现如果您在 Apache 2 中配置了别名,例如 www.example.com 和 example.com,您也应该将它们添加到 white-list。
内联代码被认为是有害的,您应该避免使用它。将所有JavaScript代码和CSS复制到单独的文件中,并将它们添加到white-list.
当你在看的时候,你可以看看其他 header 设置并安装 mod_security
进一步阅读:
https://developers.google.com/web/fundamentals/security/csp/