©
本文档使用 PHP中文网手册 发布
内容安全策略(CSP)是一个附加的安全层,有助于检测和缓解某些类型的攻击,包括跨站点脚本(XSS)和数据注入攻击。这些攻击用于从数据窃取到网站污损或恶意软件分发的所有事情。
CSP被设计为完全向后兼容(除CSP版本2,其中有在向后兼容性一些明确提到的不一致性;更多的细节在这里第1.1节)。不支持它的浏览器仍然支持实现它的服务器,反之亦然:不支持CSP的浏览器完全忽略它,像往常一样运行,默认为Web内容的标准同源策略。如果站点不提供CSP头,浏览器同样使用标准的同源策略。
要启用CSP,您需要配置您的Web服务器以返回Content-Security-Policy
HTTP标头(有时您会看到X-Content-Security-Policy
标题的提及,但这是旧版本,不需要再指定)。
或者,该<meta>
元素可用于配置策略,例如:<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
CSP的主要目标是减轻和报告XSS攻击。XSS攻击利用浏览器对从服务器接收的内容的信任。恶意脚本由受害者的浏览器执行,因为浏览器信任内容的来源,即使它不是来自它应该来自的地方。
CSP使服务器管理员可以通过指定浏览器应该认为是可执行脚本的有效来源的域来减少或消除XSS可能发生的向量。然后,兼容CSP的浏览器将仅执行从从这些列入白名单的域接收的源文件中加载的脚本,而忽略所有其他脚本(包括内联脚本和事件处理HTML属性)。
作为最终的保护形式,希望永远不允许脚本执行的站点可以选择全局禁止脚本执行。
除了限制可以加载内容的域外,服务器还可以指定允许使用哪些协议; 例如(理想情况下,从安全角度来看),服务器可以指定必须使用HTTPS加载所有内容。完整的数据传输安全策略不仅包括对数据传输实施HTTPS,还包括使用安全标记对所有Cookie进行标记,并提供从HTTP页面到其HTTPS对等方的自动重定向。网站也可能使用Strict-Transport-Security
HTTP标头来确保浏览器仅通过加密通道连接到它们。
配置内容安全策略包括将Content-Security-Policy
HTTP头添加到网页,并为其提供值以控制允许用户代理为该页加载的资源。例如,上传和显示图像的页面可能允许来自任何地方的图像,但将表单操作限制为特定的端点。正确设计的内容安全策略有助于保护页面免受跨站点脚本攻击。本文解释了如何正确构建这些头文件,并提供了示例。
您可以使用Content-Security-Policy
HTTP标头指定您的策略,如下所示:
Content-Security-Policy: policy
该策略是一个包含描述您的内容安全策略的策略指令的字符串。
使用一系列策略指令来描述策略,每个策略指令都描述特定资源类型或策略区域的策略。你的策略应该包含一个default-src
策略指令,当它们没有自己的策略时,它就是其他资源类型的回退(完整列表请参阅default-src
指令的描述)。策略需要包含一个default-src
或script-src
指令以防止内联脚本运行,并阻止使用eval()
。策略需要包含一个default-src
或style-src
指令,以限制从<style>
元素或style
属性应用内联样式。
本节提供了一些常见安全策略方案的示例。
网站管理员希望所有内容都来自网站本身(不包括子域名)。
内容安全策略:default-src'self'
网站管理员希望允许来自受信任域及其所有子域的内容(它不必与CSP设置的域相同)。
内容安全策略: default-src 'self' *.trusted.com
网站管理员希望允许Web应用程序的用户将来自任何来源的图像包含在自己的内容中,但要将音频或视频媒体限制为可信任的提供者,并且仅将所有脚本限制在承载受信任代码的特定服务器上。
内容安全策略: default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com
在此,默认情况下,仅允许来自文档来源的内容,但以下情况除外:
图像可能从任何地方加载(请注意“*”通配符)。
媒体只允许来自media1.com和media2.com(而不是来自这些网站的子域)。
可执行脚本只允许来自userscripts.example.com。
网上银行网站的网站管理员希望确保使用SSL加载其所有内容,以防止攻击者窃听请求。
内容安全策略:default-src https://onlinebanking.jumbobank.com
服务器仅允许访问通过单一来源onlinebanking.jumbobank.com通过HTTPS加载的文档。
Web邮件网站的网站管理员希望允许在电子邮件中使用HTML,以及从任何地方加载图像,但不能使用JavaScript或其他潜在危险的内容。
内容安全策略: default-src 'self' *.mailsite.com; img-src *
请注意,这个例子没有指定一个script-src
; 在示例CSP中,该站点使用default-src
指令指定的设置,这意味着脚本只能从源服务器加载。
为了简化部署,可以将CSP部署为仅限报告模式。该策略未被强制执行,但任何违规都会报告给提供的URI。此外,只有报告的标题可用于测试未来的政策修订版本,而无需实际部署。
您可以使用Content-Security-Policy-Report-Only
HTTP标头指定您的策略,如下所示:
内容安全策略报告:策略
如果Content-Security-Policy-Report-Only
标题和Content-Security-Policy
标题都出现在相同的响应中,则两个策略都会得到遵守。策略生成报告时Content-Security-Policy
强制执行头中指定的Content-Security-Policy-Report-Only
策略,但未强制实施。
如果策略包含有效的report-uri
指令,那么支持CSP的浏览器会始终发送违规报告,以便违反您建立的策略。
默认情况下,不发送违规报告。要启用违规报告,您需要指定report-uri
策略指令,至少提供一个要将报告发送到的URI:
内容安全策略: default-src 'self'; report-uri http://reportcollector.example.com/collector.cgi
然后,您需要设置您的服务器以接收报告; 它可以以您认为合适的方式存储或处理它们。
报告JSON对象包含以下数据:
document-uri
发生违规的文档的URI。referrer
违规发生的文件的referrer。blocked-uri
内容安全策略阻止加载的资源的URI。如果阻止的URI来自与document-uri不同的来源,则阻止的URI将被截断以仅包含方案,主机和端口。violated-directive
违反政策部分的名称。original-policy
原始策略由Content-Security-Policy
HTTP头指定。
让我们考虑一个位于的页面http://example.com/signup.html
。它使用以下策略,禁止除了样式表之外的所有内容cdn.example.com
。
内容安全策略: default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports
HTML的signup.html
外观如下所示:
<!DOCTYPE html><html> <head> <title>Sign Up</title> <link rel="stylesheet" href="css/style.css"> </head> <body> ... Content ... </body></html>
你能发现错误吗?样式表只允许加载cdn.example.com
,但网站尝试从它自己的原点加载一个(http://example.com
)。能够执行CSP的浏览器将下列违规报告作为POST请求发送至http://example.com/_/csp-reports
访问文档时:
{ "csp-report": { "document-uri": "http://example.com/signup.html", "referrer": "", "blocked-uri": "http://example.com/css/style.css", "violated-directive": "style-src cdn.example.com", "original-policy": "default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports" }}
正如您所看到的,报告包含违规资源的完整路径blocked-uri
。这并非总是如此。例如,当signup.html
试图从中加载CSS时http://anothercdn.example.com/stylesheet.css
,浏览器将不包含完整路径,而只包含origin(http://anothercdn.example.com
)。CSP规范给出了这种奇怪行为的解释。总之,这是为了防止泄露有关跨源资源的敏感信息。
特征 | 谷歌 | Edge | 火狐 | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|---|
Content-Security-Policy | 251 | 14 | 23.02 | 103 | 15 | 74 |
base-uri | 40 | No | 35.0 | No | 27 | 10 |
block-all-mixed-content | (Yes) | ? | 48.0 | No | (Yes) | ? |
child-src | 40 | No | 45.0 | No | 27 | 10 |
connect-src | 25 | 14 | 23.06 | No | 15 | 7 |
default-src | 25 | 14 | 23.0 | No | 15 | 7 |
disown-opener | No | No | No | No | No | No |
font-src | 25 | 14 | 23.0 | No | 15 | 7 |
form-action | 40 | No | 36.0 | No | 27 | 10 |
frame-ancestors | 40 | No | 33.0 | No | 26 | 10 |
frame-src | 25 | 14 | 23.0 | No | 15 | 7 |
img-src | 25 | 14 | 23.0 | No | 15 | 7 |
manifest-src | (Yes) | No | 41.0 | No | (Yes) | No |
media-src | 25 | 14 | 23.0 | No | 15 | 7 |
navigation-to | No | No | No | No | No | No |
object-src | 25 | 14 | 23.0 | No | 15 | 7 |
plugin-types | 40 | No | No7 | No | 27 | 10 |
referrer | 33 — 56 | No | 37.08 | No | (Yes) — 43 | No |
report-sample | 59 | ? | ? | ? | 46 | ? |
report-to | No | No | No | No | No | No |
report-uri | 25 | 14 | 23.0 | No | 15 | 7 |
require-sri-for | 54 | No | 49.0 | No | 41 | No |
sandbox | 25 | 14 | 50.0 | 10 | 15 | 7 |
script-src | 25 | 14 | 23.0 | No | 15 | 7 |
strict-dynamic | 52 | No | 52.0 | No | 39 | No |
style-src | 25 | 14 | 23.0 | No | 15 | 7 |
upgrade-insecure-requests | 43 | No9 | 42.0 | No | 30 | No |
worker-src | 59 | No | No10 | No | 48 | No |
Feature | Android | Chrome for Android | Edge mobile | Firefox for Android | IE mobile | Opera Android | iOS Safari |
---|---|---|---|---|---|---|---|
Content-Security-Policy | (Yes) | (Yes) | (Yes) | 23.0 | ? | ? | 7.15 |
base-uri | (Yes) | (Yes) | No | 35.0 | No | ? | 9.3 |
block-all-mixed-content | (Yes) | (Yes) | ? | 48.0 | No | ? | ? |
child-src | (Yes) | (Yes) | No | 45.0 | No | ? | 9.3 |
connect-src | (Yes) | (Yes) | ? | 23.0 | No | ? | 7.1 |
default-src | (Yes) | (Yes) | ? | 23.0 | No | ? | 7.1 |
disown-opener | No | No | No | No | No | No | No |
font-src | (Yes) | (Yes) | ? | 23.0 | No | ? | 7.1 |
form-action | (Yes) | (Yes) | No | 36.0 | No | ? | 9.3 |
frame-ancestors | ? | (Yes) | No | 33.0 | No | ? | 9.3 |
frame-src | (Yes) | (Yes) | ? | 23.0 | No | ? | 7.1 |
img-src | (Yes) | (Yes) | ? | 23.0 | No | ? | 7.1 |
manifest-src | (Yes) | (Yes) | No | 41.0 | No | ? | No |
media-src | (Yes) | (Yes) | ? | 23.0 | No | ? | 7.1 |
navigation-to | No | No | No | No | No | No | No |
object-src | (Yes) | (Yes) | ? | 23.0 | No | ? | 7.1 |
plugin-types | (Yes) | (Yes) | No | No | No | ? | 9.3 |
referrer | 33 — 56 | 33 — 56 | No | 37.08 | No | (Yes) — 43 | No |
report-sample | 59 | 59 | ? | ? | ? | 46 | ? |
report-to | No | No | No | No | No | No | No |
report-uri | (Yes) | (Yes) | ? | 23.0 | No | ? | 7.1 |
require-sri-for | 54 | 54 | No | 49.0 | No | 41 | No |
sandbox | (Yes) | (Yes) | ? | 50.0 | 10 | ? | 7.1 |
script-src | (Yes) | (Yes) | ? | 23.0 | No | ? | 7.1 |
strict-dynamic | 52 | 52 | No | No | No | 39 | No |
style-src | (Yes) | (Yes) | ? | 23.0 | No | ? | 7.1 |
upgrade-insecure-requests | 43 | 43 | No | 42.0 | No | 30 | No |
worker-src | 59 | 59 | No | No | No | 48 | No |
1.在Chrome 14中作为X-Webkit-CSP标头实现。
2.在Firefox 4中作为X-Content-Security-Policy头部实施。
3.作为X-Content-Security-Policy头部实现,只支持'sandbox'指令。
4.在Safari 6中实现为X-Webkit-CSP头。
5.在iOS 5.1中作为X-Webkit-CSP头部实现。
6.在Firefox 50之前,<a>元素的ping属性未被connect-src覆盖。
7.请参阅Bugzilla错误1045899。
8.将被删除,请参阅Bugzilla错误1302449。
9.正考虑未来发布。
10.参见Bugzilla错误1302667。
内容安全政策
内容安全政策只读报告
WebExtensions中的内容安全性
在Firefox开发者工具中显示安全和隐私政策