web安全策略
Content Security Policy (CSP) is a security mechanism that helps protect against content injection attacks, such as Cross Site Scripting (XSS). It's a declarative policy that lets you give the browser a whitelist of where it can load resources from, whether the browser can use inline styles or scripts, and whether it can use dynamic JavaScript evaluation—such as through the use of eval. If there's an attempt to load a resource from somewhere that isn't on this whitelist, loading of that resource is blocked.
内容安全策略(CSP)是一种安全机制,可帮助防止内容注入攻击,例如跨站点脚本(XSS)。 这是一种声明性策略,可让您向浏览器提供白名单,其中包括可从何处加载资源,浏览器是否可以使用内联样式或脚本以及是否可以使用动态JavaScript评估(例如通过使用eval 。 如果尝试从不在此白名单上的某个位置加载资源,则会阻止该资源的加载。
CSP is currently a Candidate Recommendation published by the W3C WebApplication Security Working Group. It's delivered to the browser via the Content-Security-Policy HTTP header, which contains one or more directives that whitelist domains from which the browser is allowed to load resources. CSP 1.0 has the following directives:
CSP当前是W3C Web应用程序安全性工作组发布的候选建议书。 它通过Content-Security-Policy HTTP标头传递到浏览器,该标头包含一个或多个指令,该指令将允许浏览器从中加载资源的域列入白名单。 CSP 1.0具有以下指令:
default-src
default-src
script-src
script-src
object-src
object-src
style-src
style-src
img-src
img-src
media-src
media-src
frame-src
frame-src
font-src
font-src
connect-src
connect-src
The default-src, as the name suggests, sets the default source list for the remaining directives. If a directive isn't explicitly included in the CSP header, it will fall back to using the values in the default-src list.
顾名思义, default-src为其余指令设置默认源列表。 如果指令未明确包含在CSP标头中,它将退回到使用default-src列表中的default-src 。
All directives follow the same pattern:
所有指令都遵循相同的模式:
self is used to refer to the current domain
self用于引用当前域
one or more URLs can be specified in a space-separated list 可以在一个用空格分隔的列表中指定一个或多个URLnone indicates that nothing should be loaded for a given directive e.g. object-src 'none' indicates that no plugins—such as Flash or Java—should be loaded.
none表示不应为给定指令加载none ,例如object-src 'none'表示不应加载任何插件(如Flash或Java)。
At its simplest, we could define a CSP to load resources only from the current domain as follows:
简单地说,我们可以定义一个CSP,使其仅从当前域中加载资源,如下所示:
Content-Security-Policy: default-src 'self';If an attempt to load a resource from any other domain is made, it is blocked by the browser, and a message is logged to the console:
如果尝试从任何其他域加载资源,则该资源将被浏览器阻止,并在控制台中记录一条消息:
By default, too, CSP restricts the execution of JavaScript by disallowing inline scripts and dynamic code evaluation. This, combined with whitelisting where resources can be loaded from, goes a long way to preventing content injection attacks. For example, an XSS attack attempt to inject an inline script tag would be blocked:
同样,默认情况下,CSP通过禁止内联脚本和动态代码评估来限制JavaScript的执行。 这与可以从中加载资源的白名单相结合,对于防止内容注入攻击大有帮助。 例如,将阻止XSS攻击尝试插入嵌入式脚本标签:
As too would any attempt to load an external script that wasn't included in the CSP:
同样,任何尝试加载CSP中未包含的外部脚本的尝试:
Paths aren't currently supported in the URLs, so you can't lock down your site to only serve CSS from http://cdn.example.com/css. You have to make do with specifying the domain only—for example, http://cdn.example.com. You can, however, use wildcards—for example, to specify all subdomains of a given domain, such as *.mycdn.com.
URL当前不支持路径,因此您不能将站点锁定为仅从http://cdn.example.com/css提供CSS。 您只需要指定域即可,例如,http://cdn.example.com。 但是,您可以使用通配符,例如,指定给定域的所有子域,例如* .mycdn.com。
Subsequent directives don't inherit their rules from previous directives. Each directive you include in the CSP header must explicitly list the domains / subdomains it allows. Here default-src and style-src both include self, and script-src and style-src both contain http://cdn.example.com:
后续指令不会从先前的指令继承其规则。 您包含在CSP标头中的每个指令必须明确列出其允许的域/子域。 这里default-src和style-src都包含self , script-src和style-src都包含http://cdn.example.com:
Content-Security-Policy: default-src 'self'; style-src 'self' http://cdn.example.com; script-src http://cdn.example.com;If you need to use data URLs for loading resources, you'll need to include data: in your directive—for example, img-src 'data:';.
如果您需要使用data URL来加载资源,则需要在指令中包括data: ,例如img-src 'data:'; 。
Aside from listing domains, two further features supported by script-src and style-src are unsafe-inline and unsafe-eval:
除了列出域之外, script-src和style-src支持的另外两个功能是unsafe-inline和unsafe-eval :
unsafe-inline can be used by style-src and script-src to indicate that inline <style> and <script> tags are allowed. CSP uses an opt-in policy. That is, if you don't include unsafe-inline, then all inline <style> and <script> tags are blocked. unsafe-inline also permits inline style attributes for CSS, and permits inline event handlers (onclick, onmouseover etc.) and javascript: URLs (such as <a href="javascript:foobar()">).
style-src和script-src可以使用unsafe-inline来指示允许使用内联<style>和<script>标记。 CSP使用加入策略。 也就是说,如果您不包括unsafe-inline ,则所有内联<style>和<script>标记都将被阻止。 unsafe-inline还允许CSS的内联style属性,并允许内联事件处理程序(onclick,onmouseover等)和javascript: URL(例如<a href="javascript:foobar()"> )。
unsafe-eval can be used by script-src. Again, it uses an opt-in policy, so if your script-src doesn't explicitly include unsafe-eval, any dynamic code evaluation—which includes the use of eval, the Function constructor, and passing strings to setTimeout and setInterval—is blocked.
unsafe-eval可以由script-src 。 同样,它使用选择加入策略,因此,如果您的script-src没有明确包含unsafe-eval ,则任何动态代码评估(包括使用eval ,Function构造函数以及将字符串传递给setTimeout和setInterval受阻。
Browser support for CSP 1.0 is pretty good, with Internet Explorer being the usual elephant in the room: IE10 and IE11 have partial support for CSP via the X-Content-Security-Policy header, but even then they only appear to support the optional sandbox directive.
浏览器对CSP 1.0的支持非常好,Internet Explorer经常成为会议室中的笨蛋:IE10和IE11通过X-Content-Security-Policy标头对CSP进行了部分支持,但即使如此,它们似乎也仅支持可选的sandbox指令 。
I mentioned earlier that any violation of your CSP will be logged to the browser console. Whilst that may be fine when your site is under development, it's not really practical when you deploy your CSP to production.
我之前提到过,任何违反CSP的行为都会记录到浏览器控制台中。 尽管在开发站点时可能会很好,但将CSP部署到生产环境中却并不实际。
Instead, you can use the report-uri to log all CSP violations. This directive takes a URL as its value, and makes an HTTP POST request to this URL when a CSP violation is detected. The request body contains a JSON object that is populated with details of the violation.
相反,您可以使用report-uri记录所有CSP违规行为。 该指令将URL作为其值,并在检测到CSP违规时对此URL发出HTTP POST请求。 请求主体包含一个JSON对象,其中填充了违规的详细信息。
To illustrate this, suppose we have a CSP as follows:
为了说明这一点,假设我们有一个CSP,如下所示:
Content-Security-Policy: default-src 'self'; report-uri: https://example.com/csp/report;This means the browser is only permitted to load resources from our own domain. However, our site uses Google Analytics, so it attempts to load JavaScript from www.google-analytics.com. This violates our CSP, so the following JSON is submitted via a HTTP POST request to our report-uri:
这意味着仅允许浏览器从我们自己的域中加载资源。 但是,我们的网站使用Google Analytics(分析),因此它尝试从www.google-analytics.com加载JavaScript。 这违反了我们的CSP,因此以下JSON是通过HTTP POST请求提交给我们的report-uri :
{ "csp-report": { "blocked-uri:" "https://ajax.googleapis.com" "document-uri:" "http://example.com/index.html" "original-policy": "default-src 'self'; report-uri http://example.com/csp/report" "referrer:" "" "violated-directive": "default-src 'self'" } }If you're thinking of implementing CSP, you can take your CSP for a dry run by using the Content-Security-Policy-Report-Only HTTP header instead of Content-Security-Policy. This works just the same way as the CSP header, but it only reports on violations without actually enforcing the policy by blocking restricted resources. You can even use both headers at the same time, enforcing one policy while monitoring the effect any changes might have in the other.
如果您打算实施CSP,则可以使用Content-Security-Policy-Report-Only HTTP标头而不是Content-Security-Policy来进行CSP的Content-Security-Policy-Report-Only运行。 这与CSP标头的工作方式相同,但是只报告违规情况,而没有通过阻止受限制的资源实际执行策略。 您甚至可以同时使用两个标头,在监视一项更改对另一种更改可能产生的影响的同时,执行一个策略。
I mentioned earlier that CSP is sent an HTTP header. Setting HTTP headers can be done directly on the server in your server's configuration file(s):
前面提到,CSP发送了一个HTTP标头。 可以直接在服务器的配置文件中的服务器上设置HTTP标头:
# Apache config Header set Content-Security-Policy "default-src 'self';" # IIS Web.config <system.webServer> <httpProtocol> <customHeaders> <add name="Content-Security-Policy" value="default-src 'self';" /> </customHeaders> </httpProtocol> </system.webServer> # nginx conf file add_header Content-Security-Policy "default-src 'self';";Alternatively, many programming languages / frameworks support adding HTTP headers programmatically—such as PHP's header, or Node's setHeader—so you could use these to set your CSP header:
另外,许多编程语言/框架都支持以编程方式添加HTTP标头(例如PHP的标头或Node的setHeader) ,因此您可以使用它们来设置CSP标头:
# PHP example header("Content-Security-Policy: default-src 'self'"); # Node.js example request.setHeader("Content-Security-Policy", "default-src 'self'");Let’s have a look at how Facebook and Twitter implement CSP. First, here's Facebook (line breaks added for readability):
让我们看一下Facebook和Twitter如何实现CSP。 首先,这里是Facebook(添加了换行符以提高可读性):
default-src *; script-src https://*.facebook.com http://*.facebook.com https://*.fbcdn.net http://*.fbcdn.net *.facebook.net *.google-analytics.com *.virtualearth.net *.google.com 127.0.0.1:* *.spotilocal.com:* 'unsafe-inline' 'unsafe-eval' https://*.akamaihd.net http://*.akamaihd.net *.atlassolutions.com; style-src * 'unsafe-inline'; connect-src https://*.facebook.com http://*.facebook.com https://*.fbcdn.net http://*.fbcdn.net *.facebook.net *.spotilocal.com:* https://*.akamaihd.net wss://*.facebook.com:* ws://*.facebook.com:* http://*.akamaihd.net https://fb.scanandcleanlocal.com:* *.atlassolutions.com http://attachment.fbsbx.com https://attachment.fbsbx.com;Note how Facebook makes use of wildcards for both subdomains, as well as port numbers in connect-src.
请注意,Facebook如何在两个子域中使用通配符以及connect-src端口号。
Here's the CSP used by Twitter:
这是Twitter使用的CSP:
default-src https:; connect-src https:; font-src https: data:; frame-src https: twitter:; frame-ancestors https:; img-src https: data:; media-src https:; object-src https:; script-src 'unsafe-inline' 'unsafe-eval' https:; style-src 'unsafe-inline' https:; report-uri https://twitter.com/i/csp_report?a=NVQWGYLXFVZXO2LGOQ%3D%3D%3D%3D%3D%3D&ro=false;Notice how the directives all contain https:, thus enforcing SSL.
请注意,指令全都包含https:从而强制执行SSL。
CSP Level 2 is currently a Candidate Recommendation, and defines some new directives and security measures:
CSP 2级目前是候选建议书,它定义了一些新的指令和安全措施:
base-uri controls whether the document is allowed to manipulate the base URI of the page.
base-uri控制是否允许文档操作页面的基本URI。
child-src replaces frame-src.
child-src替换frame-src 。
form-action controls the document's ability to submit HTML forms.
form-action控制文档提交HTML表单的能力。
frame-ancestors works like the X-Frame-Options header, by controlling how this document can be embedded in other documents, and is in fact intended to replace this header.
frame-ancestors工作方式类似于X-Frame-Options头,通过控制如何将此文档嵌入其他文档中来进行,并且实际上旨在替换此头。
plugin-types controls which specific plugins can be loaded by the page—such as Flash, Java, Silverlight, etc.
plugin-types控制页面可以加载哪些特定插件,例如Flash,Java,Silverlight等。
The JSON submitted to report-uri gets a couple of extra fields: effective-directive contains the name of the directive that was violated; and status-code, which contains the HTTP status code of the requested resource, or zero if the resource wasn't requested over HTTP.
提交给report-uri的JSON有两个额外的字段: effective-directive包含被违反的指令的名称; 和status-code ,其中包含所请求资源的HTTP状态代码;如果未通过HTTP请求资源,则返回零。
CSP Level 2 also includes the ability for inline scripts and style sheets to be protected via nonces and hashes.
CSP 2级还具有通过随机数和哈希值保护内联脚本和样式表的功能。
A nonce is just a random string that's generated on the server, included in the CSP header, and also included on an inline script tag. So, our CSP header with a nonce will look something like this:
随机数只是在服务器上生成的随机字符串,包含在CSP标头中,还包含在内联脚本标签中。 因此,带有随机数的CSP标头将如下所示:
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-Xiojd98a8jd3s9kFiDi29Uijwdu';When rendering the page, that same nonce needs to be included in the nonce attribute on the script tag for the inline script to execute:
呈现页面时,必须在script标记的nonce属性中包含相同的现时值,才能执行内联脚本:
<script> console.log("Script won't run as it doesn't contain a nonce attribute"); </script> <script nonce="Eskdikejidojdk978Ad8jf"> console.log("Script won't run as it has an invalid nonce"); </script> <script nonce="Xiojd98a8jd3s9kFiDi29Uijwdu"> console.log('Script runs as the nonce matches the nonce in the HTTP header'); </script>To use this approach, first you compute the hash of the style or script block on the server and include this in the CSP header in the style-src or script-src respectively. Then the browser computes the hash of the style/script block before it renders the page. If the hash computed by the browser matches the one computed on the server, the style/script block is allowed to execute.
要使用此方法,首先需要计算服务器上样式或脚本块的哈希,并将其分别包含在style-src或script-src的CSP标头中。 然后,浏览器在渲染页面之前计算样式/脚本块的哈希值。 如果浏览器计算的哈希值与服务器上计算的哈希值匹配,则允许执行样式/脚本块。
Here the CSP header includes the sha256-base64–encoded hash of the string console.log('Hello, SitePoint'); in the script-src directive:
这里的CSP标头包含字符串console.log('Hello, SitePoint');的sha256-base64编码的哈希console.log('Hello, SitePoint'); 在script-src指令中:
Content-Security-Policy: default-src 'self'; script-src 'self' 'sha256-V8ghUBat8RY1nqMBeNQlXGceJ4GMuwYA55n3cYBxxvs=';When the browser renders the page, it'll compute the hash of each inline script block and compare them against the whitelisted hashes sent in the CSP header. If it finds a match, the script executes. Note that whitespace is significant. This script will be fine:
当浏览器呈现页面时,它将计算每个内联脚本块的哈希值,并将它们与CSP标头中发送的白名单哈希值进行比较。 如果找到匹配项,则脚本将执行。 请注意,空格很重要。 这个脚本很好:
<script>console.log('Hello, SitePoint');</script>The hash of these inline scripts won't match the whitelisted value in the header, so none of them will execute:
这些内联脚本的哈希值与标头中列入白名单的值不匹配,因此它们均不会执行:
<script> console.log('Hello, SitePoint');</script> <script>console.log('Hello, SitePoint'); </script> <script>console.log('Hello, World');</script>In this article, we've had a look at CSP 1.0, and how you can use its directives to whitelist where your site can load resources from. We had a look at how you can use report-uri to collect information on requests that violate your CSP, and how Facebook and Twitter use CSP today. We finished up by looking at some of the changes that are coming in CSP 2.0—in particular, how you can get more protection for your inline styles and scripts using nonces and hashes.
在本文中,我们介绍了CSP 1.0,以及如何使用其指令将站点可以从中加载资源的白名单列入白名单。 我们了解了如何使用report-uri收集有关违反CSP的请求的信息,以及Facebook和Twitter今天如何使用CSP。 最后,我们看了CSP 2.0中即将发生的一些更改,特别是如何使用现成的和哈希的方式为内联样式和脚本提供更多保护。
If you have questions about CSP and how it works, please comment below. Have you given CSP a try yet? If so, how did it go?
如果您对CSP及其工作方式有疑问,请在下面评论。 您是否尝试过CSP? 如果是这样,情况如何?
翻译自: https://www.sitepoint.com/improving-web-security-with-the-content-security-policy/
web安全策略