内容安全策略如何工作?


248

我在开发人员控制台中收到很多错误:

拒绝评估字符串

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

拒绝加载脚本

拒绝加载样式表

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

具体来说,如何...

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

最后:

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

Answers:


556

通过使用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.如何处理不同的协议?

默认情况下,仅允许标准协议。例如,要允许WebSocket,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打通您网站的安全性,但是它具有完全有效的用例。您只需要对使用它有所了解。您可以这样允许它:

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

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

你可能会拿 'self'指的是localhost,本地文件系统或同一主机上的任何内容。这并不意味着任何。这意味着与定义内容策略的文件具有相同的方案(协议),相同的主机和相同的端口的源。是否通过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


6
很棒的帖子。一件事:指定多个指令后会发生什么并不明显;示例3中的style-src设置是否优先于default-src?等等...
track0

29
因此,要允许所有内容都包含所有内容default-src *; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'; img-src * data: 'unsafe-inline'; connect-src * 'unsafe-inline'; frame-src *;
Arnold Roa 2015年

8
重要的是要知道content="default-src * 'unsafe-inline' 'unsafe-eval'"使某些Angular应用程序正常工作是必需的。
法兰盘001

2
@Mahesh那个“博客”里满是从SO复制过来的帖子。似乎没有那么多的SO用户会复制未知博客作者的内容-我知道我没有。
施劳斯

2
关于connect-src和路径的简短说明:如果要包含整个子路径,则必须使用斜杠。例如:http://foo.com/files/bar.txt如果源为http://foo.com/files,则文件将被阻止,但在以下情况下将被提供http://foo.com/files/
Griddo

15

APACHE2 MOD_HEADERS

您还可以启用Apache2 mod_headers,如果您使用Ubuntu / Debian,则在Fedora上默认已启用它,如下所示:

# First enable headers module for Apache2, 
# 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设置。

第一个参数是指令,第二个参数是要列入白名单的源。我已经添加了Google Analytics(分析)和一个广告服务器(可能有)。此外,我发现如果您具有别名,例如在Apache2中配置的www.example.com和example.com,则也应将其添加到白名单中。

内联代码被认为是有害的,应避免使用它。将所有JavaScript和CSS复制到单独的文件中,然后将其添加到白名单中。

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

进一步阅读:

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

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


2
我能够将这些指令添加到.htaccess文件中,因为我无法在共享主机上编辑Apache配置。我在report-uri.io/home/tools中找到了用于调整这些设置的出色工具。
Michael McGinnis

有什么办法可以用tomcat 7解决这个问题。我尝试添加过滤器,但是没有用。
Elshan

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.