通俗易懂的HTTPS握手过程

1,700 阅读7分钟

什么是安全?

通讯过程中具备密码安全学的四个特性,就可以认为是“安全”的。这四个特性分别是:

  1. 机密性:简单来说就是小明和小红的对话内容是加密的,通讯时用的是火星文,只有他们自己知道如何解密;
  2. 完成性:数据是不可篡改,不多也不少的;比如小明写信约小红在公园见,结果信被小强拦截下来改成商场了;
  3. 身份验证:确认对方的身份,就是“证明你真的是你”?小明给小红写情书,结果被小强(黑客)拦截下来了,伪造小红说百日做梦。
  4. 不可否认:不能否认已经发生过的行为,比如小明和小红借了1000块钱,第二天就矢口否认,小红也确实拿不出借钱的证据,只能认倒霉。

什么是 HTTPS?

HTTPS = HTTP + SSL/TLS,SSL/TLS也应用在应用层(会话层)上,只不过是给HTTP套了一层安全的壳。只要掌握SSL/TLS,也就掌握了HTTPS。

TLS 其实就是有很多子协议组成,组成一个密码套件,密码套件命名非常规范,格式很固定。如“ECDHE-RSA-AES256-GCM-SHA384” :“密钥交换算法 + 签名算法 + 对称加密算法 + 摘要算法”。

完整的意思是:“握手时使用 ECDHE 算法进行密钥交换,用 RSA 签名和身份认证,握手后的通信使用 AES 对称算法,密钥长度 256 位,分组模式是 GCM,摘要算法 SHA384 用于消息认证和产生随机数。”

对称加密

加密解密都使用同一个密钥,目前常用的只有 AES 和 ChaCha20。 但是有一个很大的问题:如何把密钥安全地传递给对方,术语叫“密钥交换”。

非对称加密

非对称加密可以解决“密钥交换”的问题。网站(服务器)秘密保管私钥,在网上任意分发公钥,你想要登录网站只要用公钥加密就行了,密文只能由私钥持有者才能解密。而黑客因为没有私钥,所以就无法解密密文。

RSA 是最著名的一种,不过由于它的安全性基于“整数分解”的数学难题,基于两个超大素数乘积作为生成密钥的材料,想要根据公钥推出私钥是非常困难的;计算过程非常复杂,运算速度很慢。实用性几乎为0;但目前主流使用的是ECC,比起 RSA,ECC 在安全强度和性能上都有明显的优势。

// 对称加密 AES128 则是 13MB/S
aes_128_cbc enc/dec 1000 times : 0.97ms, 13.11MB/s
// 非对称加密1024位
rsa_1024 enc/dec 1000 times : 138.59ms, 93.80KB/s
rsa_1024/aes ratio = 143.17
// 非对称加密2048位
rsa_2048 enc/dec 1000 times : 840.35ms, 15.47KB/s
rsa_2048/aes ratio = 868.13

混合加密(TLS 握手预备知识)

既然非对称加密能够解决密钥交换的问题,那我们完全可以先用非对称加密进行密钥交换,再用对称加密进行通讯即可。

因为非对称密钥有单向性,所谓的单向性,就是公钥加密私钥解密,私钥加密公钥解密;这样就能把对称密钥的安全交换了,后面加密解密都用对称密钥。

具体的做法是:

  • 在通信刚开始的时候使用非对称算法,比如 RSA、ECDHE,首先解决密钥交换的问题。
  • 再用随机数产生对称算法使用的“会话密钥”(session key),再用公钥加密。(只有对方的私钥能解密)
  • 拿到密文后用私钥解密,取出会话密钥。这样,双方就实现了对称密钥的安全交换,后续就不再使用非对称加密,全都使用对称加密。

但是,还会存在另外两个问题:

  1. 怎么证明你是你?即身份验证
  2. 怎么证明这个数据是你发的?数字签名/不可否认
  3. 这个数据有没有被改过?完整性。

对于完整性,采用的是摘要算法,也是常说的散列函数/哈希函数。

摘要算法只能进行加密,没有解密。所以就能通过“数字摘要”来保证数据的完整性。

不过摘要算法不具有机密性,如果明文传输也不安全,因为我们已经通过非对称加密把“会话密钥”(session key)安全交换了。所以可以利用会话密钥(对称加密)进行加密解密。这样就可以保证数据的完整性了。

那身份认证和不可否认呢?

现实生活中我们要解决这两个问题,用签名和盖章;因为混合加密用的“公钥”和“私钥”都具有单向性,完全可以同时实现“身份认证”和“不可否认”的数字签名。

数字签名的原理其实很简单,就是把公钥私钥的用法反过来,之前是公钥加密、私钥解密,现在是私钥加密、公钥解密。

但又因为非对称加密效率太低,所以私钥只加密原文的摘要,这样运算量就小的多,而且得到的数字签名也很小,方便保管和传输。

签名和公钥一样完全公开,任何人都可以获取。但这个签名只有用私钥对应的公钥才能解开,拿到摘要后,再比对原文验证完整性,就可以像签署文件一样证明消息确实是你发的。

TLS 握手过程(对照下图理解)

  1. 第一阶段: C/S两端共享Client Random、Server Random 和 Server Params信息
  • 客户端 --> 服务器:客户端的版本号、支持的密码套件,还有一个随机数(Client Random)

  • 服务端 --> 客户端:对一下客户端的版本号、选择的客户端列表的密码套件如:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384、随机数随机数(Server Random)

  • 服务端 --> 客户端:服务端证书(Server Certificate)

  • 服务端 --> 客户端:发送Server Key Exchange类型的请求,携带椭圆曲线的公钥(Server Params)用以实现密钥交换算法,另附私钥签名(预防别人假冒我,签个名盖个章)。

  • 服务端 --> 客户端:发送完毕

  1. 第二阶段: 客户端拿着服务端证书链逐级验证,再用证书的公钥验证签名,服务端身份验证成功(证书合法)
  • 客户端 --> 服务端:发送Client Key Exchange类型的请求,携带椭圆曲线的公钥(Client Params)用以实现秘钥交换算法
  1. 第三阶段: 主密钥生成
  • 客户端、服务端分别使用Client Params、Server Params 通过 ECDHE算法计算出随机值pre-master;

  • 然后用 Client Random、Server Random 和 Pre Random 三个值(随机数)作为原材料,用PRF伪随机数函数(利用密码套件的摘要算法再次强化结果值master secret的随机性)计算出主密钥 Master Secret;

  • 主密钥并不是会话秘钥,还会再用PRF扩展出更多的密钥,比如客户端发送用的会话密钥(client_write_key)、服务器发送用的会话密钥(server_write_key);避免只用一个密钥带来的安全隐患。

  • 客户端 --> 服务端:客户端发一个“Change Cipher Spec”,然后再发一个“Finished”消息,把之前所有发送的数据做个摘要,再加密一下,让服务器做个验证;

  • 服务端 --> 客户端:服务器也是同样的操作,发“Change Cipher Spec”和“Finished”消息,双方都验证加密解密 OK,握手正式结束。

总结

总体来说TLS握手就是通过交换三个随机数,然后计算出主会话密钥;由于安全性,会继续扩展出更多的临时密钥。保证通讯过程的绝对安全。

第三个随机数 pre-master 是由Client Params、Server Params 通过 ECDHE算法计算出来的,在客户端给服务端发送这个 Client Params 之前,会根据服务端给自己的签名和证书对服务器进行身份验证。所以才能保障 Client Params 安全的到达服务端。也就实现了服务器端证明了自己是真的服务器端。

如果你还有很多疑问,或者不清晰的地方,这里我强烈推荐订阅这个专栏,透视HTTP协议,讲解得非常不错。