在以前的文章中,笔者简要介绍了一下 HTTPS 的工做原理,在扩展阅读中,笔者提到了中间人攻击(Man In The Middle Attack,简称 MITM)而在本文中,笔者将进一步解释什么是中间人攻击。segmentfault
如下内容来自维基百科中的中间人攻击词条:浏览器
在 密码学和 计算机安全领域中, 中间人攻击(Man-in-the-middle attack, 缩写:MITM)是指攻击者与通信的两端分别创建独立的联系,并交换其所收到的数据,使通信的两端认为他们正在经过一个私密的链接与对方直接对话,但事实上整个会话都被攻击者彻底控制。在中间人攻击中,攻击者能够拦截通信双方的通话并插入新的内容。在许多状况下这是很简单的(例如,在一个未加密的 Wi-Fi 无线接入点的接受范围内的中间人攻击者,能够将本身做为一个中间人插入这个网络)。
简单来讲攻击者就是一个介入通讯的传话员,攻击者知道通讯双方的全部通讯内容,并且能够任意增长、删除、修改双方的通讯内容,而双方对此并不知情。安全
而中间人攻击不只仅局限于针对 HTTPS,对于开放性的链接,中间人攻击很是容易。好比在一个未加密的 Wi-Fi 网络中,一个攻击者能够很容易地将本身插入双方的通讯之中以截取或者修改通讯的内容。服务器
这就是一个典型中间人攻击的过程。在 HTTPS 中,Tom 就是客户端,Jerry 是服务端,而邮递员就是客户端和服务端之间的任何实体(包括代理服务器、路由器、反向代理服务器等等),两把钥匙分别是公钥和私钥。通讯双方并不知道(且一般很难发觉)本身其实在和中间人通讯而非直接和对方通讯。在通讯过程当中,Tom 和 Jerry 并无验证对方的身份,这就致使了邮递员能够任意查看、修改或者丢弃双方的通讯内容。网络
从上面的例子看起来,彷佛任何在通讯双方的实体均可以实施中间人攻击,那么 HTTPS 是如何防止中间人攻击的呢?要防止被中间人攻击,那么就要确保通讯中的信息来自他声称的那我的,且没有被修改过。在现实中,有多种方式能够肯定某个实体的身份,好比我的的签名 / 私章、组织的公章、甚至古时的信物。大部分状况下,只须要在信件最后盖上签上本身的名字或者盖上组织的公章,那么接收者就能够肯定这封信件就来自于他所声称的那我的 / 组织。在二进制的世界中,可使用数字签名来确保某段消息 / 某份文件确实是由他所声称的那个实体所发出来的。网站
在以前的文章中,咱们介绍过非对称加密,其中公钥是公开的,而私钥只有拥有者知道。用私钥对某个文件 / 某段消息的散列值进行签名就像一我的亲手在信件最后签上了本身的名字同样,证实这份文件 / 这段消息确实来自私钥的拥有者(由于公钥是公开的,私钥只有拥有者知道,因此若是能用其公开的公钥解开数字签名,那就证实这条消息确实来自于他私钥的拥有者),这就能够确保消息是来自他所声称的那个实体。这样,在通讯中,双方每次在写完消息以后,计算消息的散列值,并用本身的私钥加密生成数字签名,附在信件后面,接收者在收到消息和数字签名以后,先计算散列值,再使用对方的公钥解密数字签名中的散列值,进行对比,若是一致,就能够确保该消息确实是来自于对方,而且没有被篡改过。加密
不过有个问题,若是中间人在会话创建阶段把双方交换的真实公钥替换成本身的公钥了,那么中间人仍是能够篡改消息的内容而双方并不知情。为了解决这个问题,须要找一个通讯双方都信任的第三方来为双方确认身份。这就像你们都相信公证处,公证处拿着本身的公章为每一封信件都盖上了本身的章,证实这封信确实是由本人发出的,这样就算中间人能够替换掉通讯双方消息的签名,也没法替换掉公证处的公章。这个公章,在二进制的世界里,就是数字证书,公证处就是 CA(数字证书认证机构)。操作系统
数字证书就是申请人将一些必要信息(包括公钥、姓名、电子邮件、有效期)等提供给 CA,CA 在经过各类手段确认申请人确实是他所声称的人以后,用本身的私钥对申请人所提供信息计算散列值进行加密,造成数字签名,附在证书最后,再将数字证书颁发给申请人,申请人就可使用 CA 的证书向别人证实他本身的身份了。对方收到数字证书以后,只须要用 CA 的公钥解密证书最后的签名获得加密以前的散列值,再计算数字证书中信息的散列值,将二者进行对比,只要散列值一致,就证实这张数字证书是有效且未被篡改过的。设计
通讯过程的安全性自下而上就是这样保证的:代理
至此,整个信任链就创建起来了,只须要有一台设备上安装了能够信任的根证书,就能够用来分发更多安全的操做系统了。以后的全部信任链都是安全的了。
(题外话)这些设备在到消费者手里以前有没有被恶意修改,谁都不知道。密码学家想法设法想用程序而非人类(由于人类容易收到外界影响,是没法彻底信任的)来保证安全,到最后仍是离不开人类,而人类偏偏是这些精妙设计中最容易出现问题的一环。
HTTP 协议最初的时候是明文的,由于安全问题因此如今不少网站都在逐渐过渡到 HTTPS,然而对于大部分使用者来讲,他们并不知道 HTTP 和 HTTPS 之间的区别,在浏览器输入地址的时候都是直接输入 www.example.com
而非 https://www.example.com
,在大部分状况下,若是一个网站启用了 HTTPS,服务器会将这个请求使用 301
或者 302
状态码以及一个 Location
头部将请求从 80 端口重定向至使用 HTTPS 的 443 端口。可是,若是中间人劫持了使用者的网络请求,那么中间人能够阻止客户端与服务器创建 HTTPS 链接,而是一直使用不安全的 HTTP 链接,而中间人则和服务器创建正常的 HTTPS 链接,让客户端觉得本身正在和真实服务器通讯。这种攻击手法称做 SSLTrip。
为了解决这个问题,IETF(互联网工程任务小组)引入了一个策略,叫作 HSTS (HTTP Strict Transport Security, HTTP 严格传输安全)。HSTS 的做用是强制客户端与服务端创建安全的 HTTPS 链接,而非不安全的 HTTP 链接。若是一个站点启用了 HSTS 策略,那么客户端在第一次与该站点创建链接以后,在将来的一段时间内(由一个 HTTP 头部控制,这个头部为:Strict-Transport-Security),客户端与该站点的全部链接都会直接使用 HTTPS,即便客户端访问的是 HTTP,也会直接在客户端重定向到 HTTPS 链接。
假设 https://example.com
的响应头部含有 Strict-Transport-Security: max-age=31536000; includeSubDomains
,这意味着:
example.com
或者其子域名发送请求,必须采用 HTTPS 来发起链接。即便用户在地址栏里写的是 http://example.com
,那也直接重写为 https://example.com
并直接发起 HTTPS 链接。若是站点没有启用 HSTS,用户能够忽略证书无效的警告,继续创建链接,而若是站点启用了 HSTS,那么用户即便想冒风险,浏览器也不会继续访问。
HSTS 能够很大程度上防止 SSLTrip 攻击,不过这样仍是有个问题,那就是要启用 HSTS,浏览器至少要和服务器创建一次 HTTPS 链接,若是中间人一直阻止浏览器与服务器创建 HTTPS 链接,那么 HSTS 就失效了。解决这个问题有个办法,那就是将 HSTS 站点列表内置到浏览器中,这样只要浏览器离线判断该站点启用了 HSTS,就会跳过原先的 HTTP 重定向,直接发起 HTTPS 请求。