本文已参与「新人创作礼」活动,一起开启掘金创作之路。
引言
随着互联网的不断发展,信息安全越来越重视,之前使用HTTP协议的网站如今已经销声匿迹,各大公司逐步把网站升级成 HTTPS 了。其目的之一就是避免MITM,那么HTTPS就一定可以完全杜绝MITM吗?到底它是如何确保信息安全传输的?本文试图由浅入深地把 HTTPS 讲明白,相信大家看完之后一定能明白HTTPS 是如何防御MITM的。
本文讲解的内容可以作为学校的《计算机网络》课程的补充,或者是扩展,主要涉及的是应用层和传输层。不过在将HTTPS之前,先简单提一下HTTP协议。
HTTP协议安全性分析
HTTP之所以不安全,很大程度是因为明文传输。明文传输存在主要存在三大风险:窃听风险、篡改风险、冒充风险。我们先说窃听风险。中间人可以获取到通信内容,由于内容是明文,所以获取明文后有信息泄露的安全风险。
其次就是篡改风险。中间人可以篡改报文内容后再发送给对方,风险极大。冒充风险,比如你以为是在和某宝通信,但实际上是在和一个钓鱼网站通信。HTTPS 就是为了解决这三大风险而产生的,接下来我们看看 HTTPS 具体的工作原理。了解了以上内容,不难猜到 HTTPS 就是为了解决上述三个风险而生的,一般我们认为安全的通信需要包括以下四个原则: 机密性、完整性,身份认证和不可否认。
- 机密性:即对数据加密,解决了窃听风险,因为即使被中间人窃听,由于数据是加密的,他也拿不到明文;
- 完整性:指数据在传输过程中没有被篡改,不多不少,保持原样,中途如果哪怕改了一个标点符号,接收方也能识别出来,从来判定接收报文不合法;
- 身份认证:确认对方的真实身份,即证明“我是我”的问题,这样就解决了冒充风险,用户不用担心访问的是某宝结果却在和钓鱼网站通信的问题;
- 不可否认: 即不可否认已发生的行为,比如小明向小红借了 1000 元,但没打借条,或者打了借条但没有签名,就会造成小红的资金损失。
接下来我们一步步来分析 HTTPS 是如何实现以满足以上四大安全通信原则的。
HTTPS防御MITM原理
HTTPS 使用了对称加密,而密钥传输则使用了非对称加密。既然 HTTP 是明文传输的,很自然的我们想到加密,给报文加密就可以解决窃听问题,既然要加密,那就需要通信双方协商好密钥。一种是通信双方使用同一把密钥,即对称加密的方式来给报文进行加解密。如下图:
从图中可以看出,使用对称加密的通信双方使用同一把密钥进行加密和解密。对称加密特点就是速度快,相对来说性能更好,这也是 HTTPS 最终采用的加密形式。 但是这里有一个关键问题:对称加密的通信双方要使用同一把密钥,这个密钥是如何协商出来的?如果通过报文的方式直接传输密钥,之后的通信其实还是在裸奔,因为这个密钥会被中间人截获甚至替换掉,这样中间人就可以用截获的密钥解密报文,甚至替换掉密钥以达到篡改报文的目的。
有人可能会想对这个密钥加密不就完了,但对方如果要解密这个密钥还是要传加密密钥给对方,依然还是会被中间人截获的,这么看来直接传输密钥无论怎样都无法摆脱俄罗斯套娃的难题,是不可行的。 这就要用到非对称加密机制,来解决单向对称密钥的传输问题。
非对称加密即加解密双方使用不同的密钥,一把作为公钥,可以公开的,一把作为私钥,不能公开,公钥加密的密文只有私钥可以解密,私钥加密的内容,也只有公钥可以解密。
私钥加密其实这个说法其实并不严谨,准确的说私钥加密应该叫私钥签名。因为私密加密的信息公钥是可以解密的,而公钥是公开的,任何人都可以拿到,用公钥解密叫做验签。
这样的话对于 server 来说,保管好私钥,发布公钥给其他 client, 其他 client 只要把对称加密的密钥加密传给 server 即可。如此一来由于公钥加密只有私钥能解密,而私钥只有 server 有,所以能保证 client 向 server 传输是安全的,server 解密后即可拿到对称加密密钥,这样交换了密钥之后就可以用对称加密密钥通信了。
但是问题依然没有解决, server 怎么把公钥安全地传输给 client 呢。如果直接传公钥,也会存在被中间人调包的风险。
数字证书就是解决公钥传输的信任问题。如何解决公钥传输问题呢?举个例子,员工入职时,企业一般会要求提供学历证明,显然不是任何机构颁发的学历都可以,这个学历必须由第三方权威机构(Certificate Authority,简称 CA)即教育部颁发。同理,server 也可以向 CA 申请证书,在证书中附上公钥,然后将证书传给 client,证书由站点管理者向 CA 申请,申请的时候会提交 DNS 主机名等信息,CA 会根据这些信息生成证书。
这样当 client 拿到证书后,就可以获得证书上的公钥,再用此公钥加密对称加密密钥传给 server 即可。看起来确实很完美,不过在这里依然要思考两个问题:一是如何验证证书的真实性,如何防止证书被篡改。想象一下上个例子中我们提到的学历,企业如何认定你提供的学历证书是真是假呢?答案是用学历编号,企业拿到证书后用学历编号在学信网上一查就知道证书真伪了,学历编号其实就是我们常说的数字签名,可以防止证书造假。回到 HTTPS 上,证书的数字签名该如何产生的呢?一图胜千言:
1、 首先使用一些摘要算法(如 MD5)将证书明文(如证书序列号,DNS 主机名等)生成摘要,然后再用第三方权威机构的私钥对生成的摘要进行加密(签名)。至于为什么要生成摘要再加密而不是直接加密,是因为使用非对称加密是非常耗时的。如果把整个证书内容都加密生成签名的话,客户端验验签也需要把签名解密,证书明文较长,客户端验签就需要很长的时间,而用摘要的话,会把内容很长的明文压缩成小得多的定长字符串,客户端验签的话就会快得多。
2、客户端拿到证书后也用同样的摘要算法对证书明文计算摘要,两者一笔对就可以发现报文是否被篡改了。至于为什么一定要用第三方权威机构(CA)私钥对摘要进行加密,是因为摘要算法是公开的,中间人可以替换掉证书明文,再根据证书上的摘要算法计算出摘要后把证书上的摘要也给替换掉!这样 client 拿到证书后计算摘要发现一样,误以为此证书是合法就中招了。所以必须要用 CA 的私钥给摘要进行加密生成签名,这样的话 client 得用 CA 的公钥来给签名解密,拿到的才是未经篡改合法的摘要(私钥签名,公钥才能解密)。
server 将证书传给 client 后,client 的验签过程如下:
这样的话,由于只有 CA 的公钥才能解密签名,如果客户端收到一个假的证书,使用 CA 的公钥是无法解密的,如果客户端收到了真的证书,但证书上的内容被篡改了,摘要比对不成功的话,客户端也会认定此证书非法。
到这里其实问题依然没有解决,CA 公钥要怎么安全地传输给 client ?如果还是从 server 传输到 client,依然无法解决公钥被调包的风险。实际上此公钥是存在于 CA 证书上,而此证书(也称 Root CA 证书)被操作系统信任,内置在操作系统上的,无需通过网络传输,不论是chrome浏览器还是其它的浏览器,里面都有内置的被信任的证书。如下图:
server 传输 CA 颁发的证书,客户收到证书后使用内置 CA 证书中的公钥来解密签名,验签即可,这样的话就解决了公钥传输过程中被调包的风险。
到这里问题依然没有被彻底解决。就是如何防止证书被调包。因为任何站点都可以向第三方权威机构申请证书,中间人也不例外。正常站点和中间人都可以向 CA 申请证书,获得认证的证书由于都是 CA 颁发的,所以都是合法的。那么此时中间人不就可以在传输过程中将正常站点发给 client 的证书替换成自己的证书呢,如下所示:
答案是不行,因为客户端除了通过验签的方式验证证书是否合法之外,还需要验证证书上的域名与自己的请求域名是否一致,中间人中途虽然可以替换自己向 CA 申请的合法证书,但此证书中的域名与 client 请求的域名不一致,client 会认定为不通过!
通过上面的证书调包我们有这么一种思路。大家想想,HTTPS 既然是加密的, charles 这些中间人为啥能抓到明文的包?其实就是用了证书调包这一手法,在用 charles 抓 HTTPS 的包之前我们都需要先安装 charles 的证书。这个证书里有 charles 的公钥,这样的话 charles 就可以将 server 传给 client 的证书调包成自己的证书,client 拿到后就可以用你安装的 charles 证书来验签等,验证通过之后就会用 charles 证书中的公钥来加密对称密钥了。整个流程如下:
由此可知,charles 这些中间人能抓取 HTTPS 包的前提是信任它们的 CA 证书,然后就可以通过替换证书的方式进行瞒天过海,所以千万不要随便信任第三方的证书,避免安全风险。
OK,本期就到这里,从理论上来说,HTTPS杜绝了MITM的可能性,所以把网站升级为HTTPS还是非常有必要的。通过以上分析,在浏览器内置的证书没有问题的前提下,无论如何都是无法进行MITM的,这也是我佩服HTTPS的原因。