HTTPS 加密过程讲解

1,388 阅读8分钟

HTTP 协议是一个非常棒的协议,使用起来很简单、方便。但是万物皆有两面性,HTTP 也不例外,它存在着比较大的安全问题:

  1. 通信过程不会加密,使用明文,内容可能会被窃听

    由于 HTTP 本身并不具备加密功能,所以就无法对请求或者响应的内容进行加密,这一切都是用明文发送的。等到了 TCP/IP 那一层,就可能被黑客窃听。其实就算加密了,我们发送的包也会被窃听,只不过他们解密不了。

  2. 不验证通信方的身份,可能会遭遇伪装

    在 HTTP 通信中,不存在确定通信方的处理步骤,这就造成了可能客户端是伪装的,也可能服务器是伪装的。

  3. 无法证明报文的完整性,可能已经被篡改

    使用 HTTP 没法确定接受到的请求或响应有没有修改过。于是,在传输过程中,内容被修改了,接收方也完全不知道。所以说,可能在客户端与服务器之间,存在一个中间者,肆意的修改着请求和响应,也叫做中间人攻击。

为了解决上面的这些问题,HTTPS 就来了。但是 HTTPS 并不是一种新的协议,它只是在 HTTP 上加入了加密处理和认证机制。本来 HTTP 会直接和TCP 进行通信,在 HTTPS 中,会先和 SSL(Secure Socket Layer) 通信,再由 SSL 和 TCP 进行通信。也叫做 HTTP Secure 简称 HTTPS。

其实 HTTPS 使用了 SSL ( Secure Socket Layer ) 和 TLS ( Transport Layer Security ) 这两个协议。最开始的时候只有 SSL,后来根据 SSL 3.0 制订了 TLS 1.0、TLS 1.1 和 TLS 1.2。TLS 是以 SSL 为原型开发的协议,可以理解为是一个衍生的关系一类安全协议,于是乎,有时候我们会统称两个协议为 SSL。

下面我们来看 HTTPS 是如何解决上面提到的关于 HTTP 的三个问题的。

  1. HTTP 通信过程不会加密,使用明文,内容可能会被窃听

    针对这一点,HTTPS 中在把传输的数据进行了加密。说到加密,就不得不提起两大类加密算法:对称加密和非对称加密。

    对称加密就是指加密、解密用同一份密钥。最直观的例子就是电视里的密码本。通信的双方都拿着一个密码本,根据密码本去发消息;收到消息后,也根据密码本去解析。这其实会有一个问题,那就是密钥传输至关重要。对称加密的密钥千万不能泄露,在军队中,万一密码本被间谍拿去了,整个情报网就都被破了。

    另外还一种非对称加密。它有一个公钥,有一个私钥。一般来说,是使用公钥加密、私钥解密。(注意这里是说一般情况下,也有可能私钥加密,公钥解密的,等会我们就会介绍)。如果使用公钥进行加密了,只有私钥才能把数据解密出来。这时候就可以放心的把公钥给对方,传输过程中就不用担心被人窃取了,即便被窃取了,对方也无法进行解密。当然了,这个时候要把私钥偷偷的藏好。

    由于在传输过程中,密钥会被泄露,只让我们选择一种通信的加密手段的话,肯定就选择非对称加密了:比如客户端持有一份公钥、一份私钥,并把公钥传输给服务器。当服务器发消息过来的时候,就用客户端的公钥加密一下;同理,客户端也保存一份服务端的公钥......想得是很好,但是非对称加密和对称加密比起来,要慢。于是乎,真实的情况是结合了两种的优点,使用非对称加密算法传输对称加密的密钥,等传输完毕后使用对称加密算法进行加密。

  2. 不验证通信方的身份,可能会遭遇伪装

    这一点就是用证书去解决,靠权威机构颁发的证书,比如,你肯定听过,HTTPS 过期了之类的话。HTTPS 的证书就是要去发证书的机构去认证的,每年大概几百块的样子。等后面讲流程的时候我们来看他具体是怎么做的。

  3. 无法证明报文的完整性,可能已经被篡改

    HTTP 协议无法知道报文有没有被修改,但是我们可以借助 SSL 协议,使用它,我们发送数据的时候会带上一种叫做 MAC (Message Authentication Code) 的报文摘要,靠它就能知道报文有没有被修改。

下面我们来看具体的 HTTPS 加密的过程。

  1. 客户端发送 Client Hello 开始通信,同时发送过去 SSL 版本、它支持的加密组件列表,还会生成一个随机数,后面要用,姑且记作随机数 A。

  2. 服务端回应一个 Server Hello,同时把它会从客户端的加密组件列表中选择一个,发送回去,当然了 SSL 版本也要发回去。并且也和上一步一样,给客户端返回一个随机数,记作随机数 B。

  3. 服务端发送证书,这个证书就是权威机构给颁布的,里面有服务端的公钥。后续,等客户端收到,验证无误后,要用这个公钥把后续的对称加密的密钥发过来。

    这里是怎么验证证书的合法性呢?这里就用到私钥加密&公钥解密了。权威机构在颁布证书的时候,会对它的证书做摘要,生成指纹,再使用它的私钥对这段指纹进行加密,生成一个数字签名。当接收方收到证书后,先用证书指定的算法对证书做摘要,然后再用公钥对数字签名解密,如果和摘要的结果一致就证明是可信的。

  4. 服务端发送 Server Hello Done 报文,好了,第一阶段就结束了。

  5. 当客户端收到证书后,验证的方法就是从本机的证书中找,大多数浏览器都内置了一些备受信赖的证书。接下来客户端进行验证,验证确实是可信的,好了,就使用上一步服务端发来证书里的公钥去加密自己生成的一个随机数 Pre-master 。这个阶段也叫发送 Client Key Exchange 报文。

  6. 接着,还是客户端发送 Change Cipher Spec 报文。这个是用来提示服务端使用 Pre-master Secret 密钥加密的。那这个 Pre-master Secret 是什么呢?在第 1、2 步中,客户端、服务端各自生成了一个随机数,并发送给了对方。同时双方也都有随机数 Pre-master。对称密钥就是随机数 A 、随机数 B、Pre-master 三者生成的。也就是后续加密过程中使用的对称密钥。

  7. 客户端发送 Finished 报文。该报文包含一个整体校验值,用于判断完整性。

  8. 服务端发送 Change Cipher Spec 报文,告诉客户端可以使用那个对称密钥

  9. 服务端发送 Finished 报文。

  10. 服务端、客户端的 Finished 报文交换完毕,SSH 的连接就建立完成了,后续就是发送 HTTP 请求了...

上面是 TLS 1.2 的实现,看数目就知道交换次数太多了,于是在 TLS 1.3 做了优化。

  1. 协议规定好仅仅支持几种加密套件,客户端支持的加密套件变得比较少,在发送时,会生成这几种加密方式所有的公钥、私钥。并把所有的公钥发给服务端

  2. 服务端选择一种,然后把相应的公钥发给客户端

  3. 客户端根据服务端发来的公钥加自己的私钥生成对称加密的密钥

  4. 服务端也做第三步这样的事情。值得注意的是,3、4 生成的密钥是一样的。

  5. 这样就能交换信息了 ~

image.png

上面只需要 1 个 RTT 就搞定了。

上面,还觉得优化不够,于是就有了 session 缓存、session ticket、0 RTT 的优化策略。

说起来,整个过程还是很绕、很麻烦的。由于没有对协议方面有实际的接触,理解起来也有点费劲。写完之后,还是有一点疑惑,最大的疑惑还是对 HTTP 为什么不安全的没有一个直观的理解,只知道它有这些缺点。大家能理解我的感受吗?只是知道 HTTP 有这些缺点,但是也就只是知道而已,并不清楚现实中到底怎么去攻击,或许后续实际的抓包走一遍流程就更清晰了。我看耗子叔的博客,也有见他有类似的经历,看了那么多 TCP/IP 协议的知识,只有真实到了机房在知道到底是什么。

不过对 HTTPS 的加密过程算是比较熟悉了,算是达到自己的目的了吧。