HTTPS 在我们日常中经常能用到,我们经常说 HTTPS 安全,那么你知道它为什么安全吗?有些同学会说:是因为加密啊,那么你知道它是怎么加密的吗?

前言

HTTPS 在我们日常中经常能用到,我们经常说 HTTPS 安全,那么你知道它为什么安全吗?有些同学会说:是因为加密啊,那么你知道它是怎么加密的吗?

如果你对此不是很明白,欢迎阅读本文,希望能让你解开 HTTPS 的迷雾,但如果你是大神级别的人物,那么请轻喷,因为我也不是很懂。。

HTTP

在说 HTTPS 之前,我们需要先知道 HTTP,HTTP 是基于 TCP 协议的一个无状态协议,如果你不是很懂欢迎阅读我上一篇文章,在浏览器输入 URL 回车之后发生了什么,此文讲解了一个 HTTP 请求的过程。

缺点:

  1. 使用明文进行传输,内容可能被窃听
  2. 不验证通信方的身份,通信方的身份可能是伪装
  3. 无法证明报文的完整性,报文有可能被篡改

HTTPS

HTTPS 并不是一个新协议,而是 HTTP 先和 SSL/TLS,再由 SSL/TLS 和 TCP 通信。也就是说 HTTPS 使用了隧道进行通信。

为什么不直接对 HTTP 报文进行加密,而是多加一层 SSL/TLS 呢?因为 HTTP 报文分为报文首部和报文主体,如果只对发送内容进行加密(也就是报文主体),而未加密的报文首部信息也会导致信息不安全。

在开始讲之前我们需要介绍一下加密算法。

加密算法

加密算法的实现原理是公开的,读者可能觉得这观点很奇怪,很多开发者喜欢设计千奇百怪的算法,窃以为别人并不知道,其实自行设计的算法根本不具备严格的数学模型,很容易被攻破。流行的密码学算法其算法实现是公开的,经过了长时间的考验。

对称加密

简单来说就是加密和解密都是通过同一个密钥,比如我要传输的明文是 5201314,我在传输前将明文的所有数字+1,得到:6302425,然后接收方根据相同的密钥将密文进行解密,得到明文。

一般的对称加密算法是使用 XOR(异或) 这个特点,例如:

var a = 5201314 // 明文
var b = 123456 // 密钥
var c = a ^ b // 加密 
var d = c ^ b // 解密 => 5201314 

如果对按位操作符感兴趣可以阅读我之前的文章:深入理解按位操作符

一次性加密

上面这个例子就是一次性加密,在不知道密钥的情况下,理论上是无法破解,因为即便你遍历了所有情况,但由于你不确定破译出来的是不是原文,所以这就是它无法破解的原因。这个理论是香农(C.E.Shannon)于 1949 年通过数学方法加以证明的。

DES 加密

DES 是 1977年美国联邦信息处理标准中采用的一种对称加密算法,但是在 1998 年已经被成功破解,耗时紧紧22小时,目前不再推荐使用。

它是一种把 64 位明文加密成 64 位密文的对称加密算法,也就是一次性只能加密 64 位,如果超过了 64 位,就需要进行分组加密。

对称加密还有很多种,想要了解更多可以查看这篇文章:漫游对称加密算法

对称加密的缺点

无论对称加密算法再怎么复杂,它们都有一个共同的弱点,就是

  • 如何传输密钥

如果我们要和接收方进行通信,我们需要提前协商好一个密钥,那么这个如何才能保证密钥能安全地送达,而不会落到中间人手中?

自然是将密钥进行加密,但如何依然使用对称加密,那是不是又需要另外一个密钥?所以这就陷入死循环了。

这时候就要介绍密码学上伟大的发明:RSA(公钥私钥密码算法),也就是非对称加密算法。

非对称加密算法

1977年,三位数学家Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密。这种算法用他们三个人的名字命名,叫做RSA算法

非对称加密有公钥和私钥,也就是私钥加密的密文只有公钥才能解密,公钥加密的密文只有私钥才能解密。

关于原理部分我认为阮一峰老师的这篇文章RSA算法原理已经讲得很通俗易懂了,这里不再赘述。

非对称加密的缺点

非对称加密虽然安全,至今都无法被破解,但也不是完全没有缺点的,一个比较显著的缺点就是加密时需要经过大量的计算,消耗计算机资源。

HTTPS 采用的加密方式

对称加密特点:

  • 优点:运算速度快
  • 缺点:密钥容易被获取

非对称加密特点:

  • 优点:更安全
  • 缺点:运算速度慢

很明显,如果 HTTPS 采用非对称加密的话,会消耗大量的计算资源,那么有没有一种方式可以解决这个问题呢?有的。

我们知道对称加密的缺点就是密钥的分发问题,既然这样,我们可以使用非对称加密对密钥进行加密,保证只有通信双方知道密钥后,接着就可以使用对称加密进行通信。

认证

但依然存在一个很严重的问题就是:公钥如何分发?

因为客户端无法确认公钥是来自服务器还是来自中间人,所以需要一个客户端和服务器双方都信赖的第三方机构,配分配公钥,这个机构就叫做 数字证书认证机构(CA,Certificate Authority)。

进行 HTTPS 通信时,服务器会把证书发送给客户端,客户端取得其中的公开密钥之后,先进行验证,如果验证通过,就可以开始通信。

但依然存在问题:证书怎么安全传输? 被篡改了怎么办?

使用数字签名就好了,简单来说就是将公钥和个人信息用一个 Hash 算法生成一个信息摘要。我们知道 Hash 算法有个极好的特征,只要输入的数据有一点点变化,那生成的信息摘要就会发生巨变,这样就可以防止别人修改原始内容。

但还有个问题就是,如何防止别人冒充 CA?

如果连 CA 都无法信任的话,那么之前的一切都是徒劳的,所以必须打破僵局,我们必须信任 CA。

CA 是像树一样分级的,在操作系统/浏览器中都会内置一些顶层的 CA 证书,而这些顶层 CA 会为上层的 CA 做信用背书。

说到底其实我们相信的是操作系统/浏览器,如果中间人连这个都可以伪装,那么我们就没有安全可言了。

HTTPS 中的 TLS / SSL 协议

能让 HTTPS 带来安全性的是其背后的 TLS 协议。它源于九十年代中期在 Netscape 上开发的称为安全套接字层(SSL)的协议。到 20 世纪 90 年代末,Netscape 将 SSL 移交给了 IETF,IETF 将其重命名为 TLS,并从此成为该协议的管理者。许多人仍将 Web 加密称作 SSL,即使绝大多数服务已切换到仅支持 TLS。

TLS/SSL 协议位于应用层和传输层 TCP 协议之间,注意 TLS/SSL 并不是只有 HTTP 才能使用,而是位于应用层的协议都可以使用,换句话说 TLS/SSL 协议 是用于加密应用层协议并传递给下层的 TCP。

TLS 粗略的划分又可以分为 2 层:

  • 靠近应用层的握手协议 TLS Handshaking Protocols
  • 靠近 TCP 的记录层协议 TLS Record Protocol

TLS 握手协议还能细分为 5 个子协议:

  • change_cipher_spec (在 TLS 1.3 中这个协议已经删除,为了兼容 TLS 老版本,可能还会存在)
  • alert
  • handshake
  • application_data
  • heartbeat (这个是 TLS 1.3 新加的,TLS 1.3 之前的版本没有这个协议)

TLS/SSL 可以查看以下流程:

握手失败

浏览器访问 HTTPS 网站的时候,在握手阶段可能会存在错误,比如证书的有效期过期、证书是自签名证书、客户端和服务器无法协商出一致的密码套件,遇到类似的情况,浏览器会出现一个错误页面,告知用户存在的问题。

一般握手失败时,浏览器会直接告诉用户该网站不安全。

其实 TLS / SSL 协议的原理是很复杂的,如何感兴趣可以看一下《深入浅出 HTTPS》这本书。

参考文献