深入理解HTTPS加解密原理

以下文章来源于 接水怪,文章内容有少许改动。


每篇文章都希望你能收获到东西,这篇将带你深入 HTTPS 加解密原理,希望看完能够有这些收获:

  • 明白 HTTPS 到底解决了什么问题

  • 理解对称加密与非对称加密的原理和使用场景

  • 明白 CA 机构和根证书到底起了什么作用

Why HTTPS

近几年来,各大公司都在大力推进 HTTPS 的建设。Google Chrome 将非 HTTPS 的网站标注为「不安全」,苹果要求 APP 中需要使用 HTTPS 进行通信,微信小程序也要求使用 HTTPS 协议。那么,我们为什么非要做这么一件事呢?

我们先来看看 HTTP。HTTP(Hypertext Transfer Protocol)超文本传输协议,是一种用于分布式、协作式和超媒体信息系统的应用层协议,可以说 HTTP 是当代互联网通信的基础。

但是,HTTP 有着一个致命的缺陷,那就是内容是明文传输的,没有经过任何加密,而这些明文数据会经过 WiFi、路由器、运营商、机房等多个物理设备节点,如果在这中间任意一个节点被监听,传输的内容就会完全暴露,,这一攻击手法叫做 MITM(Man In The Middle)中间人攻击。

举个例子,稍微有点长,但这个例子透露出了怪怪我对安全如此痴迷的原因😝~~

可以拿小时候上课传纸条来类比,你坐在教室靠墙的一边,想要传一句「晚上放学操场我等你」给坐在窗边的小红,中间要经过六七个人的传递。虽然你把纸条对折了一下,但是防君子不防小人,中间的所有人都可以很轻易地打开纸条看到你想要说什么。

只是看还好,如果有小刚也喜欢小红,看到你俩马上就要甜甜蜜蜜地回家了,心有不甘,换了一张纸条,改成了「晚上放学你自己回家吧,我要去网吧玩游戏」

小红看到你要抛弃她自己去玩游戏,非常伤心,开始在纸条上质问「说好的一起回家呢,为什么要去打游戏,哼」

在小红的纸条传回来的路上,小刚又改了纸条「你玩你的游戏去吧,我要和小刚回家」

于是,你和小红都倍感伤心,小刚横刀夺爱,而你一头雾水。


回忆一下几年前遍地都是的运营商劫持,当你访问一个本来很正常的网页,但页面上却莫名其妙出现了一些广告标签、跳转脚本、欺骗性的红包按钮,甚至有时候本来要下载一个文件,最后下下来却变成了另外一个完全不同的东西,这些都是被运营商劫持了 HTTP 明文数据的现象。

运营商劫持

为了解决 HTTP 明文传输数据可能导致的安全问题,1994 年网景公司提出了 HTTPS(HyperText Transfer Protocol Secure)超文本传输安全协议,数据通信仍然是 HTTP,但利用 SSL/TLS 加密数据包

HTTPS 实现原理

前面说到,HTTPS 其实就是将 HTTP 的数据包再通过 SSL/TLS 加密后传输,那么 SSL/TLS 又是什么呢?

SSL(Secure Sockets Layer)安全套接层和 TLS(Transport Layer Security)传输层安全协议其实是一套东西

网景公司在 1994 年提出 HTTPS 协议时,使用的是 SSL 进行加密。后来 IETF(Internet Engineering Task Force)互联网工程任务组将 SSL 进一步标准化,于 1999 年公布第一版 TLS 协议文件 TLS 1.0。目前最新版的 TLS 协议是 TLS 1.3,于 2018 年公布。

工作流程

我们先来看看 HTTPS 的加解密流程。

HTTPS 的加解密流程

  1. 用户在浏览器发起 HTTPS 请求(如 https://www.jieshuiguai.com/),默认使用服务端的 443 端口进行连接;

  2. HTTPS 需要使用一套 CA 数字证书,证书内会附带一个公钥 Pub,而与之对应的私钥 Private 保留在服务端不公开;

  3. 服务端收到请求,返回配置好的包含公钥 Pub 的证书给客户端;

  4. 客户端收到证书,校验合法性,主要包括是否在有效期内、证书的域名与请求的域名是否匹配,上一级证书是否有效(递归判断,直到判断到系统内置或浏览器配置好的根证书),如果不通过,则显示 HTTPS 警告信息,如果通过则继续;

  5. 客户端生成一个用于对称加密的随机 Key,并用证书内的公钥 Pub 进行加密,发送给服务端;

  6. 服务端收到随机 Key 的密文,使用与公钥 Pub 配对的私钥 Private 进行解密,得到客户端真正想发送的随机 Key

  7. 服务端使用客户端发送过来的随机 Key 对要传输的 HTTP 数据进行对称加密,将密文返回客户端;

  8. 客户端使用随机 Key 对称解密密文,得到 HTTP 数据明文;

  9. 后续 HTTPS 请求使用之前交换好的随机 Key 进行对称加解密。

对称加密与非对称加密

又是对称加密又是非对称加密,一会公钥一会私钥一会随机 Key,为什么要这么复杂呢,一套搞到底不好么?

对称加密是指有一个密钥,用它可以对一段明文加密,加密之后也只能用这个密钥来解密得到明文。如果通信双方都持有密钥,且天知地知你知我知,绝对不会有别的人知道,那么通信安全自然是可以得到保证的(在密钥足够强的情况下)。

然而,在 HTTPS 的传输场景下,服务端事先并不知道客户端是谁,你也不可能在事先不通过互联网和每一个网站的管理员都悄悄商量好一个通信密钥出来,那么必然存在一个密钥在互联网上传输的过程,如果在传输过程中被别人监听到了,那么后续的所有加密都是无用功。

这时,我们就需要另一种神奇的加密类型,非对称加密。

非对称加密有两个密钥,一个是公钥,另一个是私钥。一般来说,公钥用来加密,这时密文只能用私钥才能解开。

那么,当客户端发起连接请求,服务端将公钥传输过去,客户端利用公钥加密好信息,再将密文发送给服务端,服务端里有私钥可以解密。

但是,当服务端要返回数据,如果用公钥加密,那么客户端并没有私钥用来解密,而如果用私钥加密,客户端虽然有公钥可以解密,但这个公钥之前就在互联网上传输过,很有可能已经有人拿到,并不安全,所以这一过程只用非对称加密是不能满足的。

注意,严格来讲,私钥并不能用来加密,只能用作签名使用,这是由于密码学中生成公钥私钥时对不同变量的数学要求是不同的,因此公钥私钥抵抗攻击的能力也不同,在实际使用中不可互换。签名的功能在 HTTPS 里也有用到,下文中会说明。

只有一组公钥私钥只能保证单程的加解密,那么如果我们准备两组公钥私钥呢,是不是可以解决这个问题?来看下面这个过程。

  1. 服务端有非对称加密的公钥 A1,私钥 A2;

  2. 客户端有非对称加密的公钥 B1,私钥 B2;

  3. 客户端向服务端发起请求,服务端将公钥 A1 返回给客户端;

  4. 浏览器收到公钥 A1,将自己保存的公钥 B1 发送给服务端;

  5. 之后浏览器所有向客户端发送的数据,使用公钥 B1 加密,客户端可以使用私钥 B2 解密;

  6. 客户端所有向服务端发送的数据,使用公钥 A1 加密,服务端可以使用私钥 A2 解密。

此时,两条传输方向的数据都经过非对称加密,都能保证安全性,那么为什么不采用这种方案呢?

最主要的原因是非对称加解密耗时要远大于对称加解密,对性能有很大损耗,大家的使用体验很差。

所以,我们才最终选用了上文介绍到非对称加密 + 对称加密的方案,再复习一下↓↓↓😝

  1. 服务端有非对称加密的公钥 A1,私钥 A2;

  2. 客户端发起请求,服务端将公钥 A1 返回给客户端;

  3. 客户端随机生成一个对称加密的密钥 K,用公钥 A1 加密后发送给服务端;

  4. 服务端收到密文后用自己的私钥 A2 解密,得到对称密钥 K,此时完成了安全的对称密钥交换,解决了对称加密时密钥传输被人窃取的问题

  5. 之后双方通信都使用密钥 K 进行对称加解密。

看起来是一个非常完美的方案,兼顾了安全性和性能,但是,真的就安全了么?

CA 颁发机构

依然考虑中间人攻击的情况,非对称加密的算法都是公开的,所有人都可以自己生成一对公钥私钥。

当服务端向客户端返回公钥 A1 的时候,中间人将其替换成自己的公钥 B1 传送给浏览器。

而浏览器此时一无所知,傻乎乎地使用公钥 B1 加密了密钥 K 发送出去,又被中间人截获,中间人利用自己的私钥 B2 解密,得到密钥 K,再使用服务端的公钥 A1 加密传送给服务端,完成了通信链路,而服务端和客户端毫无感知。

HTTPS中间人

出现这一问题的核心原因是客户端无法确认收到的公钥是不是真的是服务端发来的。为了解决这个问题,互联网引入了一个公信机构,这就是 CA。

服务端在使用 HTTPS 前,去经过认证的 CA 机构申请颁发一份数字证书,数字证书里包含有证书持有者、证书有效期、公钥等信息,服务端将证书发送给客户端,客户端校验证书身份和要访问的网站身份确实一致后再进行后续的加密操作。

但是,如果中间人也聪明一点,只改动了证书中的公钥部分,客户端依然不能确认证书是否被篡改,这时我们就需要一些防伪技术了。

这中间人也太坏了吧!!!

前面说过,非对称加密中一般公钥用来加密,私钥用来解密,虽然私钥加密理论上可行,但由于数学上的设计这么做并不适合,那么私钥就只有解密这个功能了么?

私钥除了解密外的真正用途其实还有一个,就是数字签名,其实就是一种防伪技术,只要有人篡改了证书,那么数字签名必然校验失败。具体过程如下

  1. CA 机构拥有自己的一对公钥和私钥

  2. CA 机构在颁发证书时对证书明文信息进行哈希

  3. 将哈希值用私钥进行加签,得到数字签名

明文数据和数字签名组成证书,传递给客户端。
  1. 客户端得到证书,分解成明文部分 Text 和数字签名 Sig1

  2. 用 CA 机构的公钥进行解签,得到 Sig2(由于 CA 机构是一种公信身份,因此在系统或浏览器中会内置 CA 机构的证书和公钥信息)

这里的Sig2应该是解签后的哈希值,然后和本地用哈希算法进行哈希得到的哈希值对比,如果相等证明证书没有被篡改

  1. 用证书里声明的哈希算法对明文 Text 部分进行哈希得到 H

  2. 当自己计算得到的哈希值 H 与解签后的 Sig2 相等,表示证书可信,没有被篡改

这时,签名是由 CA 机构的私钥生成的,中间人篡改信息后无法拿到 CA 机构的私钥,保证了证书可信。

注意,这里有一个比较难以理解的地方,非对称加密的签名过程是,私钥将一段消息进行加签,然后将签名部分和消息本身一起发送给对方,收到消息后对签名部分利用公钥验签,如果验签出来的内容和消息本身一致,表明消息没有被篡改。

在这个过程中,系统或浏览器中内置的 CA 机构的证书和公钥成为了至关重要的环节,这也是 CA 机构公信身份的证明,如果系统或浏览器中没有这个 CA 机构,那么客户端可以不接受服务端传回的证书,显示 HTTPS 警告。

实际上 CA 机构的证书是一条信任链,A 信任 B,B 信任 C,以掘金的证书为例,掘金向 RapidSSL 申请一张证书,而 RapidSSL 的 CA 身份是由 DigiCert Global 根 CA 认证的,构成了一条信任链。

各级 CA 机构的私钥是绝对的私密信息,一旦 CA 机构的私钥泄露,其公信力就会一败涂地。之前就有过几次 CA 机构私钥泄露,引发信任危机,各大系统和浏览器只能纷纷吊销内置的对应 CA 的根证书。

有些老旧的网站会要求使用前下载安装他自己的根证书,这就是这个网站使用的证书并不能在系统内置的 CA 机构和根证书之间形成一条信任链,需要自己安装根证书来构成信任链,这里的风险就要使用者自己承担了。

证书明细

总结

HTTPS 的出发点是解决 HTTP 明文传输时信息被篡改和监听的问题。

  • 为了兼顾性能和安全性,使用了非对称加密 + 对称加密的方案。

非对称加密用于传输对称加密所需的密钥,对称加密用于传输后续请求和响应数据

  • 为了保证公钥传输中不被篡改,又使用了非对称加密的数字签名功能,借助 CA 机构和系统根证书的机制保证了 HTTPS 证书的公信力。