上一篇文章我们对HTTP标头的安全意义做了介绍,本文将为大家讲述有哪些标头可以起到实际的安全防护作用。
HTTP严格传输安全性(HSTS)HTTP标头
顾名思义,HSTS是一种强制浏览器使用安全Web连接的机制。近些年,随着域名劫持、信息泄漏等网络安全事件的频繁发生,网站安全也变得越来越重要,也促成了网络传输协议从 HTTP 到 HTTPS 再到 HSTS 的转变。采用HSTS协议的网站将保证浏览器始终连接到该网站的HTTPS加密版本,不需要用户手动在URL地址栏中输入加密地址。
该协议将帮助网站采用全局加密,用户看到的就是该网站的安全版本。HSTS的作用是强制客户端(如浏览器)使用HTTPS与服务器创建连接。服务器开启HSTS的方法是,当客户端通过HTTPS发出请求时,在服务器返回的超文本传输协议响应头中包含Strict-Transport-Security字段。非加密传输时设置的HSTS字段无效。
事实上,我们可以将HSTS称为安全Web连接链中的“缺失链接”,为什么这么说呢?
通过端到端加密,SSL为安全和授权连接奠定了基础。在理想的SSL实施中,我们可以确保在传输过程中数据不会被第三方更改或监控,或者验证我们正在与之通信的人是流量的预期接收者。
上面我之所以说是“理想的SSL实施”,是因为一些Web应用程序仅使用了部分实现,例如仅在登录和结帐页面中使用了安全连接,这就构成了巨大的安全威胁,HTTP Cookie Hijacking in the Wild (DEF CON 24会议)详细介绍了部分实现所带来的风险。
如果我们不强制所有页面通过安全连接传输,攻击者可以轻松转移浏览目标,在不安全的连接上浏览网页,或通过启动MITM攻击(如SSL Strip)将HTTPS流量转换为HTTP。
另外,过期或无效的证书对你的安全连接构成严重威胁。如果你的用户面临这些容易预防的问题,你的网站声誉也会受到损害。
有没有办法进一步可以改善你网站上的HTTPS保护?
如果要充分利用SSL,则必须将所有HTTP请求转换为HTTPS,并通过安全连接加载所有图像、脚本、样式文件和其他文件。另外,你还必须防止用户解除证书错误。
不过手动完成所有这些操作是非常困难的,尤其是在你必须阻止用户访问你的网站时出现证书错误的情况下。
值得庆幸的是,2012年11月发布的HSTS规范已经解决这个问题。我们所要做的就是在我们的网页响应上设置安全标头(Strict-Transport-Security)。使用此安全标头,我们可以将浏览器指向:
1.将所有请求转换为HTTPS连接;
2.如果出现证书相关错误(例如过期的证书),则无论如何都要阻止用户浏览网站;
3.在指定的时间内缓存此设置;
Strict-Transport-Security标头示例
以下是如何使用此标头的示例:
Strict-Transport-Security: max-age=31536000;
max-age:该指令允指定了标头内容存储在在浏览器缓存中存储的时间(以秒为单位)。
HSTS实现中有两个更重要的规范:includeSubdomains参数和preload参数。我们可以使用includeSubdomains参数在网站的所有子域上执行相同的严格且安全的连接。
第一次请求和预加载
我们只能通过安全连接设置HSTS标头,就像公钥固定(这是另一个HTTPS安全标头)一样,HSTS基于首次使用信任(Trust on First Use,TOFU)。这意味着我们必须在第一次HTTP请求时手动将用户重定向到我们网站的HTTPS版本。在其响应中,将有一个HSTS标头,这意味着浏览器将其存储在其缓存中。如果下次出现不安全(HTTP)连接时,它将自动重定向到安全连接。
黑客是否可以通过MiTM攻击覆盖第一个HTTP请求?
经过测试,黑客是可以通过MiTM攻击覆盖第一个HTTP请求的。然而,这一次,HSTS预载列表提供了帮助。
我们需要将preload指令添加到我们的HSTS标头中,以使网站有资格被包含在HSTS预加载列表中。此时浏览器将检查网站是否包含在列表中,并拒绝通过不安全的连接加载网站。
HSTS预加载列表的附加要求
将我们的网站添加到HSTS预加载列表还有一些要求:
1.你需要提供有效的证书;
2.你必须在同一主机上将HTTP重定向到HTTPS,这意味着example.com的HTTPS流量应通过example.com(而不是通过任何其他域,例如secure.example.com);
3.你必须为所有子域支持HTTPS,尤其是www子域。
4.你必须为HSTS标头设置以下值:
4.1 max-age必须至少设置为31536000秒(1年);
4.2 必须指定includeSubDomains和preload指令;
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
HTTP公钥固定(Public Key Pinning)
HTTP公钥固定(HPKP)是一种安全功能,它告诉Web客户端将特定加密公钥与某个Web服务器相关联,以降低使用伪造证书进行“MITM攻击(中间人攻击)”的风险。
为了理解HTTP公钥锁定(HPKP),让我们看看浏览器如何实现SSL握手,这是在建立安全连接之前进行的。
当我们的用户试图安全访问我们的站点时,我们将公钥发送给他们,公钥会确认他们正在与正确的一方进行对话,并将用于加密共享密钥。我们将其称为“证书”,它保存了网站名称、证书到期日期以及加密密钥中的位数等信息。
伪造的证书颁发机构及其所颁发的证书
证书中还有一条附加信息,当浏览器收到我们的证书时,它会检查我们的证书是否由受信任的证书颁发机构(CA)签名。签发给我们证书中的信息之一便是CA的名称,浏览器将使用该名称来验证我们的证书。一旦确认为真实连接,就建立了安全连接。
但是,通过几个已经发生的安全事件,我们发现无论安全动机如何,其中一个证书颁发机构都可以代表网站签署证书而不通知网站所有者!以下6个事件可以说明这一点:
1.其中一个例子发生在2011年荷兰,当时授权证书颁发机构DigiNotar遭到黑客攻击。黑客入侵数字证书授权系统,分发超过500个欺骗性数字证书给顶级互联网公司,如谷歌,Mozilla和Skype.这次黑客攻击发生在2011年6月初,但是DigiNotar直到7月中旬才发现。该公司在当年9月申请破产。其中攻击者使用这些证书监控多项Google服务,包括30万个伊朗用户的Gmail帐户。
2.在2008年和2011年也发生了类似的事件,2008年10月,StartCom被安全研究人员Mike Zusman发现可以绕过其证书所有权验证流程,可以为任意域名申请证书,但由于他申请了paypal.com和verisign.com的证书触发了StartCom高危网站黑名单被发现了此次攻击并在几分钟之内吊销了所有非法签发的证书。在2011年,攻击者又访问StartCom的根密钥,获得了生成、更新或使任何StartCom证书失效的能力。而 StartCom 将从2018年1月1日起停止颁发新证书,并且将仅提供 CRL 和 OCSP 服务两年。
如果你仍然使用 StartCom 的数码证书,我们强烈建议你尽快更换其他 SSL 供应商 (e.g. Comodo, Symantec, GeoTrust, etc.) 所提供的数码证书,以避免出现凭证错误的问题或其他影响。
3.2012年5月,火焰病毒(flamer或Skywiper)针对Microsoft 的CA证书采用了MD5碰撞攻击来攻击windows update的代码签名机制,影响了整个中东网络。
4.2012年12月,TURKTRUST(土耳其)由于管理失误下发两张二级CA证书,其中一个被用于防火墙来进行中间人监控,而被google的扎钉扎技术发现。
5.2013年12月, ANSSI(法国的网络信息安全局)颁发的二级CA证书被用于该机构中间人监控设备中,而被google的钉扎技术发现并宣布吊销其签发的二级证书,并限制只能签发法国地区域名(.fr)的证书。
6.2014年7月,NIC(印度国家信息中心)的二级CA(NICCA)被入侵,伪造签发了很多google和yahoo的域名证书,后续有问题的中间证书被吊销,该机构也被停止了证书签发,该机构的根证书机构被限制只能签发几个印度(.in)的子域名。
如何防止伪造证书
在回答这个问题之前,我们先要问一下浏览器如何自动检测某个特定域的欺诈性颁发证书,甚至将此证书报告给谷歌?
这就要依靠一种称为HTTP公钥锁定(HPKP)的机制,自从Chrome 13中引入此功能以来,网站可以使用Public-Key-Pins响应标头使浏览器知道其证书指纹(哈希值)。
浏览器将这些哈希值存储在用户的计算机上,每次访问网站时,浏览器都会根据证书的公钥生成哈希。如果哈希值与存储的值不匹配,则不会建立连接,如果设置了report-uri指令,则会将事件报告给URL。
总之,HTTP公钥锁定可以保护用户和网站免受伪造的CA证书的影响。
设置HPKP标头
Public-Key-Pins是一个安全标头,我们可以通过安全连接(HTTPS)将HPKP与每个响应一起发送回去:
Public-Key-Pins: pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g="; report-uri="http://example.com/pkp-report"; max-age=10000; includeSubDomains
HPKP指令
HPKP标头可以使用各种指令,例如max-age和report-uri,以下是一个完整的指令列表。
pin-sha256="<sha256>":这是我们在base64中编码的证书的公钥指纹,你可以在此处将多个证书的哈希值存储为备份,以防其中一个证书过期。
max-age:这是应该缓存此指令的时间长度(以秒为单位)。
includeSubdomains:HTTP公钥锁定是否覆盖子域。
report-uri:如上面的谷歌示例所述,在不匹配的情况下,该指令指定应该将HPKP策略违规报告发送到的URL,违规信息将使用HTTP POST方法发送到此URL。
你可以将HTTP公钥锁定机制设置为只在报告模式下工作,这意味着如果发生不匹配,浏览器仍将建立一个安全连接,但会将违规信息报告给report-uri指令中指定的URL。
Public-Key-Pins-Report-Only: pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g="; report-uri="http://example.com/pkp-report"; max-age=10000; includeSubDomains
根据RFC 7469,你必须设置至少2个引脚。一个用于当前证书,另一个用于备份证书。给定的Pins集包含至少一个不引用证书链中的SPKI的Pin。也就是说,主机必须设置备份引脚。
发表在EvenPaths上的研究表明,即使在Facebook和WhatsApp等大公司的网页上,也存在HPKP实施错误。这些信息是使用Alexa Top 100万域名列表收集的。虽然有些网站没有在他们的HPKP标头中固定任何证书,但也有网站固定多达17个。
哪些浏览器支持PKP安全标头?
在阅读了上述关于HPKP的内容后,我想要告诉你的是,从谷歌Chrome版本69开始,不再支持HPKP,虽然这种机制可以帮助Google捕获在野外发布的欺诈性证书。
尽管谷歌的这一做法一开始这有点令人惊讶,但如果你仔细想一想它还是有道理的。即使像Facebook这样资源丰富的公司在实施这种安全措施时也会犯错误,它可能过于复杂,无法大规模可靠地使用。
但是,有一个标头可以提供相同的保护,且不是很复杂,它就是Expect-CT HTTP标头。
Expect-CT HTTP标头
取代HPKP的标头被称为Expect-CT HTTP标头,尽管HPKP是一个有用的安全功能,但到目前为止,它并不是检测CA颁发的证书是否是恶意或阻止它们的唯一方法。通过证书颁发机构授权(CAA)和证书透明度等安全机制,攻击者仍可以在未经我们许可或不知情的情况下操纵签发给我们的证书,在某些情况下甚至可以完全阻止CA颁发这些证书。
但是这些Expect-CT HTTP标头保护措施具体是如何运作的,能否真正取代HPKP呢?
证书透明度日志
证书透明系统的核心是证书日志,证书日志是维护SSL证书记录的简单网络服务。这就是为什么我们要把讨论的安全标头被称为'Expect-CT',换句话说“期望证书会被提交给证书透明度日志”。
这些证书透明度日志可公开访问,因此管理员可以检查它们并搜索自己的域。如果在没有事先知情或授权的情况下为其域名颁发了证书,他们可以立即采取措施保护其用户。
当然,CA并没有动机为已经严格监管的证书签署过程增加更多的复杂性,这就是为什么谷歌不得不在2018年4月发布新证书时强制执行CT日志的原因。
CT日志的工作原理
证书日志有三个重要特性,证书透明度为当前的SSL证书系统添加了三个新的功能组件:
· 证书日志;
· 证书监视器;
· 证书审核员;
这些功能组件代表提供补充监控和审计服务的分立软件模块。它们不是现有SSL证书系统的替代品或替代品。事实上,这些组件不会改变基本的信任链模型,它允许客户端验证域并建立与服务器的安全连接。相反,这些组件通过为公众监督和整个SSL证书系统的审查提供支持来增强信任链模型。
此外,建议网站所有者将Expect-CT标头添加到他们的响应中。因为浏览器会决定提交给他们的证书是否遵循概述的规则,除证书外,浏览器还会检查签名证书时间戳(SCT)。此数据包含记录证书的时间戳,而浏览器则使用SCT信息检查是否符合概述的条件。
使用Expect-CT HTTP标头有没有风险?
如果我们在2015年4月的强制性开始日期之前在Google Chrome中为我们的网站颁发了证书,并且将过期日期设置为2005年,则Google无法执行证书透明度规则。否则,这将导致大量完全有效的证书不再可用,即使它们是在CT发明之前发布的。由于HPKP在Chrome中已弃用,因此无法通知我们网站是否含有非法颁发的证书。
但是,如果我们设置并强制执行Expect-CT标头,并使用max-age将该指令在浏览器中缓存一段时间。那么在连接到我们网站的过程中,凡是不符合CT要求的证书,即使是在2018年4月之前签署,也不会被接受。通过这种方式,我们消除了在不知情的情况下判定旧证书有效的风险。
我们如何实现Expect-CT标头?
首先,我们必须确保我们当前的证书支持CT,我们可以通过生成SSL实验室报告来实现。
接下来,我们可以使用如下所示的标头激活HTTP响应中的Expect-CT标头:
Expect-CT: enforce,max-age=30,report-uri="https://ABSOLUTE_REPORT_URL"
Expect-CT标头有三个指令:
max-age:这表示数据存储在浏览器缓存中的持续时间(以秒为单位)。
report-uri:这是违规报告将发送到的URL,它必须是绝对URL(例如https://example.com/report),而不是相对网址(例如/ report)。
enforce:如果存在不符合CT的证书,则指示是否应该建立连接。
你也可以在单纯报告模式下使用此模式,而该模式最初不会强制执行CT要求。
Expect-CT: max-age=30,report-uri="https://ABSOLUTE_REPORT_URL"
如果一切都如预期的那样,那么你可以选择强制执行。
Expect-CT: max-age=30,report-uri="https://ABSOLUTE_REPORT_URL", enforce
Referrer-Policy HTTP标头
Referer请求标头由于层级很复杂,容易让人产生混乱。首先,'referer'就是拼写错了的单词,正确的拼写应该是' referrer '。尽管这是一个有趣的有趣事实,它也表明纠正一个简单的错误是多么困难,如HTTP标头字段中缺少'r'。如果你还不是很懂,就想象一下,在广泛的协议中纠正一个关键安全漏洞多么困难吧!
但拼写错误并不是造成此标头难于被理解的根本原因,至于具体的原因,请先让我们来看看这个标头是如何工作的?
Referrer-Policy标头的工作原理
假设你是网站A的所有者,并且你希望访问者查看网站B。此时,你可以通过在主页上添加指向网站B的超链接来完成此操作。如果用户单击该链接,则他们的浏览器会自动将Referer标头添加到请求标头。此时,它的内容将是网站A的地址。这样做的好处是,网站B可以通过检查每个传入请求的Referer标头来查看谁链接到他们的网站。 此时,Referer标头将被添加到针对样式、图像、脚本加载和表单提交的请求中。请求看起来如下:
GET / HTTP/1.1 Host: B.com Referer: A.com
出于安全和隐私等多种原因,你可能希望将信息隐藏在Referer头中。
作为响应标头,Referrer-Policy为你提供了以下选项来帮助控制Referer请求标头。注意Referrer-Policy是如何用双r(rr)编写的。可以说,这只会增加区分Referer / Referrer拼写错误的难度,尽管这是正确的写法。
可以在HTTP响应消息中设置Referrer-Policy标头,如下所示:
Referrer-Policy: no-referrer
Referrer-Policy指令
以下是Referrer-Policy标头可以发送的所有指令信息:
" " (empty):这表示未设置Referrer-Policy,并且可以通过页面上的HTML元素设置控制引用的指令。这可以通过使用<meta>标记或使用rel或referrerpolicy属性为单个HTML标记指定策略来完成。
Referrer-Policy:
no-referrer:即使重定向页面与主机具有相同的来源,也不会添加任何Referer标头。
Referrer-Policy: no-referrer
no-referrer-when-downgrade:如果协议降级(从更安全的协议传递到安全性较低的协议,例如HTTPS到HTTP),则不会发送Referer标头,这是所有浏览器的默认行为。
Referrer-Policy: no-referrer-when-downgrade
same-origin:如果目标网站具有相同的来源(scheme、域和端口必须匹配),则仅发送Referer标头。Referrer-Policy: same-origin
origin:这会截断Referer标头中URL的路径部分,如上所述,origin包括scheme,域和端口。在协议降级期间(从HTTPS切换到HTTP),路径信息将被省略,只有原始数据将被发送到引用程序中的HTTP网站。
Referrer-Policy: origin
strict-origin:该指令将确保当协议安全级别保持不变(例如HTTPS和HTTPS)时,浏览器仅将源作为引用发送,但不会将其发送到安全级别较低的网站,例如从HTTPS发送到HTTP。
Referrer-Policy: strict-origin
origin-when-cross-origin:如果目标和主机网站具有相同的来源,则Referer标头将包含完整的URL。如果两者具有不同的来源,则只有scheme和域数据将包含在Referer头中。在协议降级的情况下,Origin数据也将通过Referer头发送到请求的HTTP网站。
Referrer-Policy: origin-when-cross-origin
strict-origin-when-cross-origin:使用此指令时,只有在目标和主机网站共享在同一协议安全级别或具有更高的协议安全级别时,才会显示Referer数据中的Origin数据。
Referrer-Policy: strict-origin-when-cross-origin
unsafe-url:浏览器将在从主机到目标网站的每个请求中共享Referer标头中的完整URL。
你应该注意到,使用此指令,即使从安全连接到不安全连接,也将共享完整的URL。此选项会使你退出浏览器的默认行为(避免协议降级中的URL可见性),因此应谨慎使用。
Referrer-Policy: unsafe-url
哪些浏览器支持Referrer-Policy安全标头?
在下图中,你可以看到哪些浏览器完全支持Referrer-Policy,哪些浏览器不支持。详细信息,请访问此链接。