内容安全策略 (CSP) 如何工作? [英] How does Content Security Policy (CSP) work?
问题描述
我在开发者控制台中收到一堆错误:
I'm getting a bunch of errors in the developer console:
拒绝评估字符串
拒绝执行内联脚本,因为它违反了以下内容安全策略指令
Refused to execute inline script because it violates the following Content Security Policy directive
拒绝加载脚本
拒绝加载样式表
这是怎么回事?内容安全策略 (CSP) 如何工作?如何使用 Content-Security-Policy
HTTP 标头?
What's this all about? How does Content Security Policy (CSP) work? How do I use the Content-Security-Policy
HTTP header?
具体来说,如何...
- ...允许多个来源?
- ...使用不同的指令?
- ...使用多个指令?
- ...处理端口?
- ...处理不同的协议?
- ...允许
file://
协议? - ...使用内联样式、脚本和标签
和
?
- ...允许
eval()
?
- ...allow multiple sources?
- ...use different directives?
- ...use multiple directives?
- ...handle ports?
- ...handle different protocols?
- ...allow
file://
protocol? - ...use inline styles, scripts, and tags
<style>
and<script>
? - ...allow
eval()
?
最后:
'self'
到底是什么意思?
- What exactly does
'self'
mean?
推荐答案
Content-Security-Policy
元标记可让您降低 XSS 攻击允许您定义可以从何处加载资源,防止浏览器从任何其他位置加载数据.这使攻击者更难将恶意代码注入您的网站.
The Content-Security-Policy
meta-tag allows you to reduce the risk of XSS attacks by allowing you to define where resources can be loaded from, preventing browsers from loading data from any other locations. This makes it harder for an attacker to inject malicious code into your site.
我用头撞了一堵砖墙,试图弄清楚为什么我一个接一个地收到 CSP 错误,但似乎没有任何关于它是如何工作的简洁明了的说明.因此,这里是我尝试简要解释 CSP 的某些要点,主要集中在我发现难以解决的问题上.
I banged my head against a brick wall trying to figure out why I was getting CSP errors one after another, and there didn't seem to be any concise, clear instructions on just how does it work. So here's my attempt at explaining some points of CSP briefly, mostly concentrating on the things I found hard to solve.
为简洁起见,我不会在每个示例中写下完整的标签.相反,我将只显示 content
属性,因此示例 content="default-src 'self'"
意味着:
For brevity I won’t write the full tag in each sample. Instead I'll only show the content
property, so a sample that says content="default-src 'self'"
means this:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
1.如何允许多个来源?
您可以简单地在指令后以空格分隔的列表形式列出您的来源:
You can simply list your sources after a directive as a space-separated list:
content="default-src 'self' https://example.com/js/"
请注意,除了特殊参数外,参数周围没有引号,例如'self'
.此外,指令后没有冒号 (:
).只是指令,然后是空格分隔的参数列表.
Note that there are no quotes around parameters other than the special ones, like 'self'
. Also, there's no colon (:
) after the directive. Just the directive, then a space-separated list of parameters.
隐式允许低于指定参数的所有内容.这意味着在上面的示例中,这些将是有效的来源:
Everything below the specified parameters is implicitly allowed. That means that in the example above these would be valid sources:
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
错误
default-src
the default policy for loading javascript, images, CSS, fonts, AJAX requests, etcscript-src
defines valid sources for javascript filesstyle-src
defines valid sources for css filesimg-src
defines valid sources for imagesconnect-src
defines valid targets for to XMLHttpRequest (AJAX), WebSockets or EventSource. If a connection attempt is made to a host that's not allowed here, the browser will emulate a400
error
还有其他的,但这些是您最有可能需要的.
There are others, but these are the ones you're most likely to need.
3.如何使用多个指令?
您可以在一个元标记中定义所有指令,方法是用分号 (;
) 终止它们:
You define all your directives inside one meta-tag by terminating them with a semicolon (;
):
content="default-src 'self' https://example.com/js/; style-src 'self'"
4.我如何处理端口?
需要通过在允许的域后添加端口号或星号来明确允许除默认端口之外的所有内容:
Everything but the default ports needs to be allowed explicitly by adding the port number or an asterisk after the allowed domain:
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
正如我提到的,您还可以使用星号来明确允许所有端口:
As I mentioned, you can also use an asterisk to explicitly allow all ports:
content="default-src example.com:*"
5.我如何处理不同的协议?
默认情况下,只允许使用标准协议.例如,要允许 WebSockets ws://
,您必须明确允许它:
By default, only standard protocols are allowed. For example to allow WebSockets ws://
you will have to allow it explicitly:
content="default-src 'self'; connect-src ws:; style-src 'self'"
^^^ web Sockets are now allowed on all domains and ports.
6.如何允许文件协议 file://
?
如果你试图这样定义它是行不通的.相反,您将使用 filesystem
参数允许它:
If you'll try to define it as such it won’t work. Instead, you'll allow it with the filesystem
parameter:
content="default-src filesystem"
7.如何使用内联脚本和样式定义?
除非明确允许,否则您不能在 <script>
标签内或在标签属性(如 onclick
)中使用内联样式定义、代码.你允许他们这样:
Unless explicitly allowed, you can't use inline style definitions, code inside <script>
tags or in tag properties like onclick
. You allow them like so:
content="script-src 'unsafe-inline'; style-src 'unsafe-inline'"
您还必须明确允许内联、base64 编码的图像:
You'll also have to explicitly allow inline, base64 encoded images:
content="img-src data:"
8.如何允许 eval()
?
我敢肯定很多人会说你不会,因为eval 是邪恶的"并且是世界末日即将来临的最有可能的原因.那些人会错的.当然,您绝对可以使用 eval 在您网站的安全性中打出重大漏洞,但它具有完全有效的用例.你只需要聪明地使用它.你允许它像这样:
I'm sure many people would say that you don't, since 'eval is evil' and the most likely cause for the impending end of the world. Those people would be wrong. Sure, you can definitely punch major holes into your site's security with eval, but it has perfectly valid use cases. You just have to be smart about using it. You allow it like so:
content="script-src 'unsafe-eval'"
9.'self'
到底是什么意思?
9. What exactly does 'self'
mean?
您可能将 'self'
理解为本地主机、本地文件系统或同一主机上的任何内容.这并不意味着其中任何一个.这意味着与定义内容策略的文件具有相同方案(协议)、相同主机和相同端口的源.通过 HTTP 为您的站点提供服务?除非你明确定义它,否则没有 https .
You might take 'self'
to mean localhost, local filesystem, or anything on the same host. It doesn't mean any of those. It means sources that have the same scheme (protocol), same host, and same port as the file the content policy is defined in. Serving your site over HTTP? No https for you then, unless you define it explicitly.
我在大多数示例中都使用了 'self'
,因为包含它通常是有意义的,但这绝不是强制性的.如果您不需要它,请忽略它.
I've used 'self'
in most examples as it usually makes sense to include it, but it's by no means mandatory. Leave it out if you don't need it.
但是等一下!我不能只使用 content="default-src *"
并完成它吗?
But hang on a minute! Can't I just use content="default-src *"
and be done with it?
没有.除了明显的安全漏洞之外,这也不会像您期望的那样工作.尽管一些文档声称它允许任何事情,但事实并非如此.它不允许内联或评估,因此要真正使您的网站更加脆弱,您可以使用:
No. In addition to the obvious security vulnerabilities, this also won’t work as you'd expect. Even though some docs claim it allows anything, that's not true. It doesn't allow inlining or evals, so to really, really make your site extra vulnerable, you would use this:
content="default-src * 'unsafe-inline' 'unsafe-eval'"
...但我相信你不会.
... but I trust you won’t.
进一步阅读:
http://content-security-policy.com
http://en.wikipedia.org/wiki/Content_Security_Policy
这篇关于内容安全策略 (CSP) 如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!