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.1、2008 年的 1.2 和去年(2018)的 1.3,每个新版本都紧跟密码学
的发展和互联⽹的现状,持续强化安全和性能,已经成为了信息安全领域中的权威标准。
⽬前应⽤的最⼴泛的 TLS 是 1.2,⽽之前的协议(TLS1.1/1.0、SSLv3/v2)都已经被认为是不安全的,各⼤浏览器即将在
2020 年左右停⽌⽀持,所以接下来的讲解都针对的是 TLS1.2。
TLS 由记录协议、握⼿协议、警告协议、变更密码规范协议、扩展协议等⼏个⼦协议组成,综合使⽤了对称加密、⾮对称加
密、⾝份认证等许多密码学前沿技术。浏览器和服务器在使⽤ TLS 建⽴连接时需要选择⼀组恰当的加密算法来实现安全通
信,这些算法的组合被称为“密码套件”(cipher suite,也叫加密套件)。
SSL/TLS分为对称加密和⾮对称加密两种⽅式。
对称加密
对称加密是指加密和解密都⽤同⼀份密钥。如下图所⽰:
AES 的意思是“⾼级加密标准”(Advanced Encryption Standard),密钥长度可以是 128、192 或 256。它是 DES 算法的替
代者,安全强度很⾼,性能也很好,⽽且有的硬件还会做特殊优化,所以⾮常流⾏,是应⽤最⼴泛的对称加密算法。
ChaCha20 是 Google 设计的另⼀种加密算法,密钥长度固定为 256 位,纯软件运⾏性能要超过 AES,曾经在移动客户端上
⽐较流⾏,但 ARMv8 之后也加⼊了 AES 硬件优化,所以现在不再具有明显的优势,但仍然算得上是⼀个不错算法。
⾮对称加密
⾮对称加密对应于⼀对密钥,称为私钥和公钥,⽤私钥加密后需要⽤公钥解密,⽤公钥加密后需要⽤私钥解密。如下图所⽰:
对称加密看上去好像完美地实现了机密性,但其中有⼀个很⼤的问题:如何把密钥安全地传递给对⽅,术语叫“密钥交换”。
因为在对称加密算法中只要持有密钥就可以解密。如果你和⽹站约定的密钥在传递途中被⿊客窃取,那他就可以在之后随意解
密收发的数据,通信过程也就没有机密性可⾔了。
这个问题该怎么解决呢?
你或许会说:“把密钥再加密⼀下发过去就好了”,但传输“加密密钥的密钥”⼜成了新问题。这就像是“鸡⽣蛋、蛋⽣鸡”,可以⽆
限递归下去。只⽤对称加密算法,是绝对⽆法解决密钥交换的问题的。
所以,就出现了⾮对称加密(也叫公钥加密算法)。
它有两个密钥,⼀个叫“公钥”(public key),⼀个叫“私钥”(private key)。两个密钥是不同的,“不对称”,公钥可以公开给
任何⼈使⽤,⽽私钥必须严格保密。
公钥和私钥有个特别的“单向”性,虽然都可以⽤来加密解密,但公钥加密后只能⽤私钥解密,反过来,私钥加密后也只能⽤公
钥解密。
⾮对称加密可以解决“密钥交换”的问题。⽹站秘密保管私钥,在⽹上任意分发公钥,你想要登录⽹站只要⽤公钥加密就⾏了,
密⽂只能由私钥持有者才能解密。⽽⿊客因为没有私钥,所以就⽆法破解密⽂。
⾮对称加密算法的设计要⽐对称算法难得多,在 TLS ⾥只有很少的⼏种,⽐如 DH、DSA、RSA、ECC 等。
RSA 可能是其中最著名的⼀个,⼏乎可以说是⾮对称加密的代名词,它的安全性基于“整数分解”的数学难题,使⽤两个超⼤素
数的乘积作为⽣成密钥的材料,想要从公钥推算出私钥是⾮常困难的。10 年前 RSA 密钥的推荐长度是 1024,但随着计算机
运算能⼒的提⾼,现在 1024 已经不安全,普遍认为⾄少要 2048 位。
ECC(Elliptic Curve Cryptography)是⾮对称加密⾥的“后起之秀”,它基于“椭圆曲线离散对数”的数学难题,使⽤特定的曲线
⽅程和基点⽣成公钥和私钥,⼦算法 ECDHE ⽤于密钥交换,ECDSA ⽤于数字签名。
⽐起 RSA,ECC 在安全强度和性能上都有明显的优势。160 位的 ECC 相当于 1024 位的 RSA,⽽ 224 位的 ECC 则相当于
2048 位的 RSA。因为密钥短,所以相应的计算量、消耗的内存和带宽也就少,加密解密的性能就上去了,对于现在的移动互
联⽹⾮常有吸引⼒。
对称加密的优点是运算速度快,缺点是互联⽹环境下⽆法将密钥安全的传送给对⽅。⾮对称加密的优点是可以安全的
将公钥传递给对⽅,但是运算速度慢。
看到这⾥,你是不是认为可以抛弃对称加密,只⽤⾮对称加密来实现机密性呢?
这⾥ TLS 把对称加密和⾮对称加密结合起来,两者互相取长补短,即能⾼效地加密解密,⼜能安全地密钥交换。其实说穿了
也很简单:
在通信刚开始的时候使⽤⾮对称算法,⽐如 RSA、ECDHE,⾸先解决密钥交换的问题。
然后⽤随机数产⽣对称算法使⽤的“会话密钥”(session key),再⽤公钥加密。因为会话密钥很短,通常只有 16 字节或 32
字节,所以慢⼀点也⽆所谓。
对⽅拿到密⽂后⽤私钥解密,取出会话密钥。这样,双⽅就实现了对称密钥的安全交换,后续就不再使⽤⾮对称加密,全都使
⽤对称加密。
这样混合加密就解决了对称加密算法的密钥交换问题,⽽且安全和性能兼顾,完美地实现了机密性。
不过这只是“万⾥长征的第⼀步”,后⾯还有完整性、⾝份认证、不可否认等特性没有实现,所以现在的通信还不是绝对安全。
数字签名与证书
⿊客虽然拿不到会话密钥,⽆法破解密⽂,但可以通过窃听收集到⾜够多的密⽂,再尝试着修改、重组后发给⽹站。因为没有
完整性保证,服务器只能“照单全收”,然后他就可以通过服务器的响应获取进⼀步的线索,最终就会破解出明⽂。
另外,⿊客也可以伪造⾝份发布公钥。如果你拿到了假的公钥,混合加密就完全失效了。你以为⾃⼰是在和“某宝”通信,实际
上⽹线的另⼀端却是⿊客,银⾏卡号、密码等敏感信息就在“安全”的通信过程中被窃取了。
所以,在机密性的基础上还必须加上完整性、⾝份认证等特性,才能实现真正的安全。
摘要算法
实现完整性的⼿段主要是摘要算法(Digest Algorithm),也就是常说的散列函数、哈希函数(Hash Function)。
你可以把摘要算法近似地理解成⼀种特殊的压缩算法,它能够把任意长度的数据“压缩”成固定长度、⽽且独⼀⽆⼆的“摘要”字
符串,就好像是给这段数据⽣成了⼀个数字“指纹”。
换⼀个⾓度,也可以把摘要算法理解成特殊的“单向”加密算法,它只有算法,没有密钥,加密后的数据⽆法解密,不能从摘要
逆推出原⽂。
摘要算法实际上是把数据从⼀个“⼤空间”映射到了“⼩空间”,所以就存在“冲突”(collision,也叫碰撞)的可能性,就如同现实
中的指纹⼀样,可能会有两份不同的原⽂对应相同的摘要。好的摘要算法必须能够“抵抗冲突”,让这种可能性尽量地⼩。
因为摘要算法对输⼊具有“单向性”和“雪崩效应”,输⼊的微⼩不同会导致输出的剧烈变化,所以也被 TLS ⽤来⽣成伪随机数
(PRF,pseudo random function)。
你⼀定在⽇常⼯作中听过、或者⽤过 MD5(Message-Digest 5)、SHA-1(Secure Hash Algorithm 1),它们就是最常⽤的
两个摘要算法,能够⽣成 16 字节和 20 字节长度的数字摘要。但这两个算法的安全强度⽐较低,不够安全,在 TLS ⾥已经被
禁⽌使⽤了。
⽬前 TLS 推荐使⽤的是 SHA-1 的后继者:SHA-2。
SHA-2 实际上是⼀系列摘要算法的统称,总共有 6 种,常⽤的有 SHA224、SHA256、SHA384,分别能够⽣成 28 字节、32
字节、48 字节的摘要。
完整性
摘要算法保证了“数字摘要”和原⽂是完全等价的。所以,我们只要在原⽂后附上它的摘要,就能够保证数据的完整性。
⽐如,你发了条消息:“转账 1000 元”,然后再加上⼀个 SHA-2 的摘要。⽹站收到后也计算⼀下消息的摘要,把这两份“指
纹”做个对⽐,如果⼀致,就说明消息是完整可信的,没有被修改。
如果⿊客在中间哪怕改动了⼀个标点符号,摘要也会完全不同,⽹站计算⽐对就会发现消息被窜改,是不可信的。
不过摘要算法不具有机密性,如果明⽂传输,那么⿊客可以修改消息后把摘要也⼀起改了,⽹站还是鉴别不出完整性。
所以,真正的完整性必须要建⽴在机密性之上,在混合加密系统⾥⽤会话密钥加密消息和摘要,这样⿊客⽆法得知明⽂,也就
没有办法动⼿脚了。
这有个术语,叫哈希消息认证码(HMAC)。
数字签名
加密算法结合摘要算法,我们的通信过程可以说是⽐较安全了。但这⾥还有漏洞,就是通信的两个端点(endpoint)。
就像⼀开始所说的,⿊客可以伪装成⽹站来窃取信息。⽽反过来,他也可以伪装成你,向⽹站发送⽀付、转账等消息,⽹站没
有办法确认你的⾝份,钱可能就这么被偷⾛了。
现实⽣活中,解决⾝份认证的⼿段是签名和印章,只要在纸上写下签名或者盖个章,就能够证明这份⽂件确实是由本⼈⽽不是
其他⼈发出的。
在这⾥,使⽤⾮对称加密⾥的“私钥”再加上摘要算法,就能够实现“数字签名”,同时实现“⾝份认证”和“不可否认”。
数字签名的原理其实很简单,就是把公钥私钥的⽤法反过来,之前是公钥加密、私钥解密,现在是私钥加密、公钥解密。
但⼜因为⾮对称加密效率太低,所以私钥只加密原⽂的摘要,这样运算量就⼩的多,⽽且得到的数字签名也很⼩,⽅便保管和
传输。
签名和公钥⼀样完全公开,任何⼈都可以获取。但这个签名只有⽤私钥对应的公钥才能解开,拿到摘要后,再⽐对原⽂验证完
整性,就可以像签署⽂件⼀样证明消息确实是你发的。
刚才的这两个⾏为也有专⽤术语,叫做“签名”和“验签”。
只要你和⽹站互相交换公钥,就可以⽤“签名”和“验签”来确认消息的真实性,因为私钥保密,⿊客不能伪造签名,就能够保证
通信双⽅的⾝份。
⽐如,你⽤⾃⼰的私钥签名⼀个消息“我是⼩明”。⽹站收到后⽤你的公钥验签,确认⾝份没问题,于是也⽤它的私钥签名消
息“我是某宝”。你收到后再⽤它的公钥验⼀下,也没问题,这样你和⽹站就都知道对⽅不是假冒的,后⾯就可以⽤混合加密进
⾏安全通信了。
数字证书和 CA
到现在,综合使⽤对称加密、⾮对称加密和摘要算法,是不是已经完美了呢?
不是的,这⾥还有⼀个“公钥的信任”问题。因为谁都可以发布公钥,我们还缺少防⽌⿊客伪造公钥的⼿段,也就是说,怎么来
判断这个公钥就是你或者某宝的公钥呢?
真是“按下葫芦⼜起了瓢”,安全还真是个⿇烦事啊,“⼀环套⼀环”的。
我们可以⽤类似密钥交换的⽅法来解决公钥认证问题,⽤别的私钥来给公钥签名,显然,这⼜会陷⼊“⽆穷递归”。但这次实在
是“没招”了,要终结这个“死循环”,就必须引⼊“外⼒”,找⼀个公认的可信第三⽅,让它作为“信任的起点,递归的终点”,构建
起公钥的信任链。
这个“第三⽅”就是我们常说的 CA(Certificate Authority,证书认证机构)。它就像⽹络世界⾥的公安局、教育部、公证中⼼,
具有极⾼的可信度,由它来给各个公钥签名,⽤⾃⾝的信誉来保证公钥⽆法伪造,是可信的。CA 对公钥的签名认证也是有格
式的,不是简单地把公钥绑定在持有者⾝份上就完事了,还要包含序列号、⽤途、颁发者、有效时间等等,把这些打成⼀个包
再签名,完整地证明公钥关联的各种信息,形成“数字证书”(Certificate)。
知名的 CA 全世界就那么⼏家,⽐如 DigiCert、VeriSign、Entrust、Let’s Encrypt 等,它们签发的证书分 DV、OV、EV 三
种,区别在于可信程度。
DV 是最低的,只是域名级别的可信,背后是谁不知道。EV 是最⾼的,经过了法律和审计的严格核查,可以证明⽹站拥有者
的⾝份(在浏览器地址栏会显⽰出公司的名字,例如 Apple、GitHub 的⽹站)。
不过,CA 怎么证明⾃⼰呢?
这还是信任链的问题。⼩⼀点的 CA 可以让⼤ CA 签名认证,但链条的最后,也就是Root CA,就只能⾃⼰证明⾃⼰了,这个
就叫“⾃签名证书”(Self-Signed Certificate)或者“根证书”(Root Certificate)。你必须相信,否则整个证书信任链就⾛不下
去了。
有了这个证书体系,操作系统和浏览器都内置了各⼤ CA 的根证书,上⽹的时候只要服务器发过来它的证书,就可以验证证书
⾥的签名,顺着证书链(Certificate Chain)⼀层层地验证,直到找到根证书,就能够确定证书是可信的,从⽽⾥⾯的公钥也
是可信的。
证书体系的弱点
证书体系(PKI,Public 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),⽤于后续⽣成会话密钥。
这个的意思就是:“我这边有这些这些信息,你看看哪些是能⽤的,关键的随机数可得留着。”
发布评论