2023年11月28日发(作者:)

⾮常详细的HTTPS分享

前⾔

1990年互联⽹诞⽣之初,就已经开始⽤超⽂本传输协议 HTTP 传输数据,这也是为什么现在⽹页地址都是以 http 开头的原

因。但是HTTP协议传输数据是明⽂传输,任意的⼈抓包就能看到传输的数据,这显然不安全。1994年,Netscape 公司⽤加

密协议增加了 HTTP,开始在 HTTP 的基础上加⼊ SSL 即安全套接层(Secure Socket Layer)。称为 "HTTP over SSL"

"HTTP Secure",也就是我们现在熟知的 HTTPS

HTTPS 其实是⼀个⾮常简单的协议,RFC ⽂档很⼩,只有短短的 7 页,⾥⾯规定了新的协议名“https”,默认端⼝号 443

⾄于其他的什么请求 - 应答模式、报⽂结构、请求⽅法、URI、头字段、连接管理等等都完全沿⽤ HTTP,没有任何新的东

西。

也就是说,除了协议名“http”和端⼝号 80 这两点不同,HTTPS 协议在语法、语义上和 HTTP 完全⼀样,优缺点也照单全

(当然要除去明⽂不安全)。

对于 http 请求还不是很了解的,可以阅读以下⼏篇⽂章

HTTP 概述

TCP 三次握⼿和四次挥⼿图解(有限状态机)

从你输⼊⽹址,到看到⽹页——详解中间发⽣的过程

漫谈 HTTP 性能优化

SSL/TLS

SSL/TLS是位于TCP/IP 7层协议中的会话层,⽤于认证⽤户和服务器,加解密数据以及维护数据的完整性,确保数据在传输

过程中不会被修改。

SSL v2 v3 两个版本,⽽ v1 因为有严重的缺陷从未公开过。SSL 发展到 v3 时已经证明了它⾃⾝是⼀个⾮常好的安全通

信协议,于是互联⽹⼯程组 IETF 1999 年把它改名为 TLS(传输层安全,Transport Layer Security),正式标准化,版本

号从 1.0 重新算起,所以 TLS1.0 实际上就是 SSLv3.1

到今天 TLS 已经发展出了三个版本,分别是 2006 年的 1.12008 年的 1.2 和去年(2018)的 1.3,每个新版本都紧跟密码学

的发展和互联⽹的现状,持续强化安全和性能,已经成为了信息安全领域中的权威标准。

⽬前应⽤的最⼴泛的 TLS 1.2,⽽之前的协议(TLS1.1/1.0SSLv3/v2)都已经被认为是不安全的,各⼤浏览器即将在

2020 年左右停⽌⽀持,所以接下来的讲解都针对的是 TLS1.2

TLS 由记录协议、握⼿协议、警告协议、变更密码规范协议、扩展协议等⼏个⼦协议组成,综合使⽤了对称加密、⾮对称加

密、⾝份认证等许多密码学前沿技术。浏览器和服务器在使⽤ TLS 建⽴连接时需要选择⼀组恰当的加密算法来实现安全通

信,这些算法的组合被称为密码套件cipher suite,也叫加密套件)。

SSL/TLS分为对称加密和⾮对称加密两种⽅式。

对称加密

对称加密是指加密和解密都⽤同⼀份密钥。如下图所⽰:

AES 的意思是⾼级加密标准Advanced Encryption Standard),密钥长度可以是 128192 256。它是 DES 算法的替

代者,安全强度很⾼,性能也很好,⽽且有的硬件还会做特殊优化,所以⾮常流⾏,是应⽤最⼴泛的对称加密算法。

ChaCha20 Google 设计的另⼀种加密算法,密钥长度固定为 256 位,纯软件运⾏性能要超过 AES,曾经在移动客户端上

⽐较流⾏,但 ARMv8 之后也加⼊了 AES 硬件优化,所以现在不再具有明显的优势,但仍然算得上是⼀个不错算法。

⾮对称加密

⾮对称加密对应于⼀对密钥,称为私钥和公钥,⽤私钥加密后需要⽤公钥解密,⽤公钥加密后需要⽤私钥解密。如下图所⽰:

对称加密看上去好像完美地实现了机密性,但其中有⼀个很⼤的问题:如何把密钥安全地传递给对⽅,术语叫密钥交换

因为在对称加密算法中只要持有密钥就可以解密。如果你和⽹站约定的密钥在传递途中被⿊客窃取,那他就可以在之后随意解

密收发的数据,通信过程也就没有机密性可⾔了。

这个问题该怎么解决呢?

你或许会说:把密钥再加密⼀下发过去就好了,但传输加密密钥的密钥⼜成了新问题。这就像是鸡⽣蛋、蛋⽣鸡,可以⽆

限递归下去。只⽤对称加密算法,是绝对⽆法解决密钥交换的问题的。

所以,就出现了⾮对称加密(也叫公钥加密算法)。

它有两个密钥,⼀个叫公钥public key),⼀个叫私钥private key)。两个密钥是不同的,不对称,公钥可以公开给

任何⼈使⽤,⽽私钥必须严格保密。

公钥和私钥有个特别的单向性,虽然都可以⽤来加密解密,但公钥加密后只能⽤私钥解密,反过来,私钥加密后也只能⽤公

钥解密。

⾮对称加密可以解决密钥交换的问题。⽹站秘密保管私钥,在⽹上任意分发公钥,你想要登录⽹站只要⽤公钥加密就⾏了,

密⽂只能由私钥持有者才能解密。⽽⿊客因为没有私钥,所以就⽆法破解密⽂。

⾮对称加密算法的设计要⽐对称算法难得多,在 TLS ⾥只有很少的⼏种,⽐如 DHDSARSAECC 等。

RSA 可能是其中最著名的⼀个,⼏乎可以说是⾮对称加密的代名词,它的安全性基于整数分解的数学难题,使⽤两个超⼤素

数的乘积作为⽣成密钥的材料,想要从公钥推算出私钥是⾮常困难的。10 年前 RSA 密钥的推荐长度是 1024,但随着计算机

运算能⼒的提⾼,现在 1024 已经不安全,普遍认为⾄少要 2048 位。

ECCElliptic Curve Cryptography)是⾮对称加密⾥的后起之秀,它基于椭圆曲线离散对数的数学难题,使⽤特定的曲线

⽅程和基点⽣成公钥和私钥,⼦算法 ECDHE ⽤于密钥交换,ECDSA ⽤于数字签名。

⽐起 RSAECC 在安全强度和性能上都有明显的优势。160 位的 ECC 相当于 1024 位的 RSA,⽽ 224 位的 ECC 则相当于

2048 位的 RSA。因为密钥短,所以相应的计算量、消耗的内存和带宽也就少,加密解密的性能就上去了,对于现在的移动互

联⽹⾮常有吸引⼒。

对称加密的优点是运算速度快,缺点是互联⽹环境下⽆法将密钥安全的传送给对⽅。⾮对称加密的优点是可以安全的

将公钥传递给对⽅,但是运算速度慢。

看到这⾥,你是不是认为可以抛弃对称加密,只⽤⾮对称加密来实现机密性呢?

这⾥ TLS 把对称加密和⾮对称加密结合起来,两者互相取长补短,即能⾼效地加密解密,⼜能安全地密钥交换。其实说穿了

也很简单:

在通信刚开始的时候使⽤⾮对称算法,⽐如 RSAECDHE,⾸先解决密钥交换的问题。

然后⽤随机数产⽣对称算法使⽤的会话密钥session key),再⽤公钥加密。因为会话密钥很短,通常只有 16 字节或 32

字节,所以慢⼀点也⽆所谓。

对⽅拿到密⽂后⽤私钥解密,取出会话密钥。这样,双⽅就实现了对称密钥的安全交换,后续就不再使⽤⾮对称加密,全都使

⽤对称加密。

这样混合加密就解决了对称加密算法的密钥交换问题,⽽且安全和性能兼顾,完美地实现了机密性。

不过这只是万⾥长征的第⼀步,后⾯还有完整性、⾝份认证、不可否认等特性没有实现,所以现在的通信还不是绝对安全。

数字签名与证书

⿊客虽然拿不到会话密钥,⽆法破解密⽂,但可以通过窃听收集到⾜够多的密⽂,再尝试着修改、重组后发给⽹站。因为没有

完整性保证,服务器只能照单全收,然后他就可以通过服务器的响应获取进⼀步的线索,最终就会破解出明⽂。

另外,⿊客也可以伪造⾝份发布公钥。如果你拿到了假的公钥,混合加密就完全失效了。你以为⾃⼰是在和某宝通信,实际

上⽹线的另⼀端却是⿊客,银⾏卡号、密码等敏感信息就在安全的通信过程中被窃取了。

所以,在机密性的基础上还必须加上完整性、⾝份认证等特性,才能实现真正的安全。

摘要算法

实现完整性的⼿段主要是摘要算法(Digest Algorithm),也就是常说的散列函数、哈希函数(Hash Function)。

你可以把摘要算法近似地理解成⼀种特殊的压缩算法,它能够把任意长度的数据压缩成固定长度、⽽且独⼀⽆⼆的摘要

符串,就好像是给这段数据⽣成了⼀个数字指纹

换⼀个⾓度,也可以把摘要算法理解成特殊的单向加密算法,它只有算法,没有密钥,加密后的数据⽆法解密,不能从摘要

逆推出原⽂。

摘要算法实际上是把数据从⼀个⼤空间映射到了⼩空间,所以就存在冲突collision,也叫碰撞)的可能性,就如同现实

中的指纹⼀样,可能会有两份不同的原⽂对应相同的摘要。好的摘要算法必须能够抵抗冲突,让这种可能性尽量地⼩。

因为摘要算法对输⼊具有单向性雪崩效应,输⼊的微⼩不同会导致输出的剧烈变化,所以也被 TLS ⽤来⽣成伪随机数

PRFpseudo random function)。

你⼀定在⽇常⼯作中听过、或者⽤过 MD5Message-Digest 5)、SHA-1Secure Hash Algorithm 1),它们就是最常⽤的

两个摘要算法,能够⽣成 16 字节和 20 字节长度的数字摘要。但这两个算法的安全强度⽐较低,不够安全,在 TLS ⾥已经被

禁⽌使⽤了。

⽬前 TLS 推荐使⽤的是 SHA-1 的后继者:SHA-2

SHA-2 实际上是⼀系列摘要算法的统称,总共有 6 种,常⽤的有 SHA224SHA256SHA384,分别能够⽣成 28 字节、32

字节、48 字节的摘要。

完整性

摘要算法保证了数字摘要和原⽂是完全等价的。所以,我们只要在原⽂后附上它的摘要,就能够保证数据的完整性。

⽐如,你发了条消息:转账 1000 ,然后再加上⼀个 SHA-2 的摘要。⽹站收到后也计算⼀下消息的摘要,把这两份

做个对⽐,如果⼀致,就说明消息是完整可信的,没有被修改。

如果⿊客在中间哪怕改动了⼀个标点符号,摘要也会完全不同,⽹站计算⽐对就会发现消息被窜改,是不可信的。

不过摘要算法不具有机密性,如果明⽂传输,那么⿊客可以修改消息后把摘要也⼀起改了,⽹站还是鉴别不出完整性。

所以,真正的完整性必须要建⽴在机密性之上,在混合加密系统⾥⽤会话密钥加密消息和摘要,这样⿊客⽆法得知明⽂,也就

没有办法动⼿脚了。

这有个术语,叫哈希消息认证码(HMAC)。

数字签名

加密算法结合摘要算法,我们的通信过程可以说是⽐较安全了。但这⾥还有漏洞,就是通信的两个端点(endpoint)。

就像⼀开始所说的,⿊客可以伪装成⽹站来窃取信息。⽽反过来,他也可以伪装成你,向⽹站发送⽀付、转账等消息,⽹站没

有办法确认你的⾝份,钱可能就这么被偷⾛了。

现实⽣活中,解决⾝份认证的⼿段是签名和印章,只要在纸上写下签名或者盖个章,就能够证明这份⽂件确实是由本⼈⽽不是

其他⼈发出的。

在这⾥,使⽤⾮对称加密⾥的私钥再加上摘要算法,就能够实现数字签名,同时实现⾝份认证不可否认

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

但⼜因为⾮对称加密效率太低,所以私钥只加密原⽂的摘要,这样运算量就⼩的多,⽽且得到的数字签名也很⼩,⽅便保管和

传输。

签名和公钥⼀样完全公开,任何⼈都可以获取。但这个签名只有⽤私钥对应的公钥才能解开,拿到摘要后,再⽐对原⽂验证完

整性,就可以像签署⽂件⼀样证明消息确实是你发的。

刚才的这两个⾏为也有专⽤术语,叫做签名验签

只要你和⽹站互相交换公钥,就可以⽤签名验签来确认消息的真实性,因为私钥保密,⿊客不能伪造签名,就能够保证

通信双⽅的⾝份。

⽐如,你⽤⾃⼰的私钥签名⼀个消息我是⼩明。⽹站收到后⽤你的公钥验签,确认⾝份没问题,于是也⽤它的私钥签名消

我是某宝。你收到后再⽤它的公钥验⼀下,也没问题,这样你和⽹站就都知道对⽅不是假冒的,后⾯就可以⽤混合加密进

⾏安全通信了。

数字证书和 CA

到现在,综合使⽤对称加密、⾮对称加密和摘要算法,是不是已经完美了呢?

不是的,这⾥还有⼀个公钥的信任问题。因为谁都可以发布公钥,我们还缺少防⽌⿊客伪造公钥的⼿段,也就是说,怎么来

判断这个公钥就是你或者某宝的公钥呢?

真是按下葫芦⼜起了瓢,安全还真是个⿇烦事啊,⼀环套⼀环的。

我们可以⽤类似密钥交换的⽅法来解决公钥认证问题,⽤别的私钥来给公钥签名,显然,这⼜会陷⼊⽆穷递归。但这次实在

没招了,要终结这个死循环,就必须引⼊外⼒,找⼀个公认的可信第三⽅,让它作为信任的起点,递归的终点,构建

起公钥的信任链。

这个第三⽅就是我们常说的 CACertificate Authority,证书认证机构)。它就像⽹络世界⾥的公安局、教育部、公证中⼼,

具有极⾼的可信度,由它来给各个公钥签名,⽤⾃⾝的信誉来保证公钥⽆法伪造,是可信的。CA 对公钥的签名认证也是有格

式的,不是简单地把公钥绑定在持有者⾝份上就完事了,还要包含序列号、⽤途、颁发者、有效时间等等,把这些打成⼀个包

再签名,完整地证明公钥关联的各种信息,形成数字证书Certificate)。

知名的 CA 全世界就那么⼏家,⽐如 DigiCertVeriSignEntrustLet’s Encrypt 等,它们签发的证书分 DVOVEV

种,区别在于可信程度。

DV 是最低的,只是域名级别的可信,背后是谁不知道。EV 是最⾼的,经过了法律和审计的严格核查,可以证明⽹站拥有者

的⾝份(在浏览器地址栏会显⽰出公司的名字,例如 AppleGitHub 的⽹站)。

不过,CA 怎么证明⾃⼰呢?

这还是信任链的问题。⼩⼀点的 CA 可以让⼤ CA 签名认证,但链条的最后,也就是Root CA,就只能⾃⼰证明⾃⼰了,这个

就叫⾃签名证书Self-Signed Certificate)或者根证书Root Certificate)。你必须相信,否则整个证书信任链就⾛不下

去了。

有了这个证书体系,操作系统和浏览器都内置了各⼤ CA 的根证书,上⽹的时候只要服务器发过来它的证书,就可以验证证书

⾥的签名,顺着证书链(Certificate Chain)⼀层层地验证,直到找到根证书,就能够确定证书是可信的,从⽽⾥⾯的公钥也

是可信的。

证书体系的弱点

证书体系(PKIPublic Key Infrastructure)虽然是⽬前整个⽹络世界的安全基础设施,但绝对的安全是不存在的,它也有弱

点,还是关键的信任⼆字。

如果 CA 失误或者被欺骗,签发了错误的证书,虽然证书是真的,可它代表的⽹站却是假的。

还有⼀种更危险的情况,CA 被⿊客攻陷,或者 CA 有恶意,因为它(即根证书)是信任的源头,整个信任链⾥的所有证书也

就都不可信了。

这两种事情并不是耸⼈听闻,都曾经实际出现过。所以,需要再给证书体系打上⼀些补丁。

针对第⼀种,开发出了 CRL(证书吊销列表,Certificate revocation list)和 OCSP(在线证书状态协议,Online Certificate

Status Protocol),及时废⽌有问题的证书。

对于第⼆种,因为涉及的证书太多,就只能操作系统或者浏览器从根上下狠⼿了,撤销对 CA 的信任,列⼊⿊名单,这样

它颁发的所有证书就都会被认为是不安全的。

HTTPS 建⽴连接

当你在浏览器地址栏⾥键⼊“https”开头的 URI,再按下回车,会发⽣什么呢?

浏览器⾸先要从 URI ⾥提取出协议名和域名。因为协议名是“https”,所以浏览器就知道了端⼝号是默认的 443,它再⽤ DNS

解析域名,得到⽬标的 IP 地址,然后就可以使⽤三次握⼿与⽹站建⽴ TCP 连接了。

HTTP 协议⾥,建⽴连接后,浏览器会⽴即发送请求报⽂。但现在是 HTTPS 协议,它需要再⽤另外⼀个握⼿过程,在

TCP 上建⽴安全连接,之后才是收发 HTTP 报⽂。

这个握⼿过程与 TCP 有些类似,是 HTTPS TLS 协议⾥最重要、最核⼼的部分,懂了它,你就可以⾃豪地说⾃⼰掌握了

HTTPS”

TLS 协议的组成

在讲 TLS 握⼿之前,我先简单介绍⼀下 TLS 协议的组成。

TLS 包含⼏个⼦协议,你也可以理解为它是由⼏个不同职责的模块组成,⽐较常⽤的有记录协议、警报协议、握⼿协议、记录协议、警报协议、握⼿协议、

变更密码规范协议等。变更密码规范协议

记录协议(Record Protocol)规定了 TLS 收发数据的基本单位:记录(record)。它有点像是 TCP ⾥的 segment,所有的其

他⼦协议都需要通过记录协议发出。但多个记录数据可以在⼀个 TCP 包⾥⼀次性发出,也并不需要像 TCP 那样返回 ACK

警报协议(Alert Protocol)的职责是向对⽅发出警报信息,有点像是 HTTP 协议⾥的状态码。⽐如,protocol_version 就是不

⽀持旧版本,bad_certificate 就是证书有问题,收到警报后另⼀⽅可以选择继续,也可以⽴即终⽌连接。

握⼿协议(Handshake Protocol)是 TLS ⾥最复杂的⼦协议,要⽐ TCP SYN/ACK 复杂的多,浏览器和服务器会在握⼿过

程中协商 TLS 版本号、随机数、密码套件等信息,然后交换证书和密钥参数,最终双⽅协商得到会话密钥,⽤于后续的混合

加密系统。

最后⼀个是变更密码规范协议(Change Cipher Spec Protocol),它⾮常简单,就是⼀个通知,告诉对⽅,后续的数据都将

使⽤加密保护。那么反过来,在它之前,数据都是明⽂的。

下⾯的这张图简要地描述了 TLS 的握⼿过程,其中每⼀个都是⼀个记录,多个记录组合成⼀个 TCP 包发送。所以,最多

经过两次消息往返(4 个消息)就可以完成握⼿,然后就可以在安全的通信环境⾥发送 HTTP 报⽂,实现 HTTPS 协议。

ECDHE 握⼿过程

刚才你看到的是握⼿过程的简要图,⼜画了⼀个详细图,下⾯我就⽤这个图来仔细剖析 TLS 的握⼿过程。

TCP 建⽴连接之后,浏览器会⾸先发⼀个“Client Hello”消息,也就是跟服务器打招呼。⾥⾯有客户端的版本号、⽀持的

密码套件,还有⼀个随机数(Client Random),⽤于后续⽣成会话密钥。

这个的意思就是:我这边有这些这些信息,你看看哪些是能⽤的,关键的随机数可得留着。