前阵子某公司同事拿了个抓包文件来找我,说某个内部系统的接口访问时好时坏,偶尔卡住十几秒然后报错。我打开抓包软件扫了一眼,发现大量TLS握手中的重传报文,再往下看,原来他压根没把HTTPS加密过程当回事——以为是“握个手、换个密钥”那么简单。这一下我突然意识到,很多同学平时调接口写代码都能跑通,但真正被问到“HTTPS到底怎么加密的”时,脑子里往往只有“证书”“公钥”“私钥”这三个词,中间那段“双方怎么协商出同一个密钥”的戏码,反而是模糊的。这篇就用几分钟的阅读节奏,把HTTPS从握手到加密传输的完整过程拆开揉碎了讲一遍,顺便把我实际排障中踩过的坑一并放出来,希望对正在跟接口调试、证书配置较劲的人有点帮助。
1. 拆词看本质:HTTPS不是一种加密算法,而是两套算法接力
很多人以为HTTPS就是把HTTP报文“加密一下”,这个说法不算错,但太笼统了。HTTPS全称是HTTP over TLS,也就是在HTTP协议和TCP之间,加了一层TLS(传输层安全协议)作为安全通道。HTTP本身仍是纯文本,是TLS把整条通道加密了。
这层TLS真正工作的时候,用的不是一种加密算法,而是两套算法接力:非对称加密管密钥协商,对称加密管数据收发。
1.1 对称加密:快,但密钥怎么送是死穴
对称加密的特点是加密和解密用同一把密钥。比如AES-GCM、ChaCha20这类算法,运算速度非常快,适合在一条长连接里持续加密大量数据。问题在于:通信双方必须共享同一把“会话密钥”,可这条会话密钥总不能直接放在HTTP报文里传来传去吧?谁抓到包就等于拿到了解密钥匙,那加密等于白做。
1.2 非对称加密:慢,但能解决密钥配送问题
非对称加密有一对钥匙,公钥可以公开,私钥自己保存。用公钥加密的数据只有私钥能解,反过来,用私钥签名的东西别人能用公钥验真。这类算法(RSA、ECDSA等)速度比对称加密慢好几个数量级,不适合直接加密海量业务数据,但它有一个不可替代的能力:让双方在一条被监控的信道上,安全地协商出同一个对称密钥。
HTTPS的完整思路就是“非对称加密先铺路,对称加密再跑车”。握手阶段用非对称加密解决身份验证和密钥协商,握手完成后,所有真实HTTP数据全部由对称加密接管。理解了这个分工,后面所有流程都能对号入座。
2. 第一幕:服务器先掏“身份证”——证书与数字签名在验什么
TLS握手第一步,客户端先得搞清楚和自己说话的是不是真身。这个动作对应的是HTTPS里最常被提到的词:证书。
2.1 证书里到底有什么
服务器证书不是一串随机字符串,它是一份结构化的数字文件,里面核心字段包括:
- 证书持有者(服务器的域名或组织名)
- 证书的公钥
- 证书有效期
- 签发者(谁给这张证书签了字)
- 数字签名(签发者对证书内容做的签名)
我见过不少同学把“证书”等同于“公钥”,这是最常见的误解。证书更像一个“身份证夹”,公钥只是身份信息之一,真正关键的是那张数字签名——它决定了这张证书到底可不可信。
2.2 数字签名的验证链路
证书里的数字签名是证书签发机构(简称CA)用自己的私钥,对证书内容算一遍摘要后生成的。客户端验证的时候,会拿CA的公钥去验这个签名,只要验签通过,就说明证书内容没有被篡改过,而且确实由那个CA签发。
但这里有个现实问题:浏览器怎么拿到CA公钥?答案是CA的公钥预装在操作系统或浏览器的信任库里。而且现代证书不是根CA直接签服务器证书,而是根CA先签发一个“中间证书”,中间证书再给服务器证书签名。客户端验证时顺着链往上捋,直到找到自己信任的根证书,这个链条叫证书链。
2.3 一次验证失败的实测案例
有次某内部系统上线后,安全扫描工具一直报证书不可信,但浏览器访问却正常。我再细查,发现部署时只给了服务器证书,没把中间证书一并配上去。浏览器在某些情况下能自动补全中间证书,但扫描工具、curl这类程序不会自动补齐,于是验证链断在了中间环节。
如果你用curl访问某个HTTPS接口报“unable to get local issuer certificate”,优先检查服务器是否把完整的证书链(服务器证书+中间证书)一起配上了。这是部署环节排名第一的证书问题。
3. 第二幕:公开信道上怎么悄悄定暗号——密钥协商的关键博弈
证书验完后,双方就要开始协商“会话密钥”了。这一段是整个HTTPS加密过程最容易被误解的地方,也是我建议所有人花精力看懂的核心环节。
3.1 最经典的RSA密钥交换流程
在TLS 1.2及更早版本里,最常见的方式是RSA密钥交换,逻辑其实不复杂:
- 客户端生成一个随机数,叫pre-master secret。
- 客户端用服务器证书里的公钥加密这个随机数,然后发给服务器。
- 服务器用自己的私钥解密,得到同一个pre-master secret。
- 客户端和服务器各自用这个pre-master secret,再加上双方在握手里交换的两个随机数,推演出相同的会话密钥。
这个方案思路清晰,但它有一个致命弱点:如果服务器私钥泄露,所有历史上用这把公钥加密过的通信都能被解密。换句话说,没有前向保密。
3.2 ECDHE:临时密钥带来的前向保密
后来主流方案变成了ECDHE(椭圆曲线迪菲-赫尔曼密钥交换)。用大白话讲,就是双方在公开信道上各自选择一个临时私钥,再根据椭圆曲线算法算出各自的临时公钥,互相交换临时公钥后,通过数学关系计算出同一个共享密钥。
这里的关键点在于“临时”:每次握手双方都生成一对全新的临时密钥,握手结束就丢弃。就算服务器长期私钥哪天泄露出去了,攻击者也解不开历史上已经结束的会话,因为那次的共享密钥依赖的是当时的临时私钥。这就是所谓的前向保密,也是TLS 1.3里彻底移除了RSA密钥交换、只保留ECDHE类方案的原因。
我之前用抓包软件看过一次完整握手,报文里既有ServerHello里的随机数,又有ServerKeyExchange里携带的椭圆曲线参数和签名。建议大家在本地抓一次包,把报文中每个字段对应到流程里看,远比背流程图有效。
3.3 握手过程全链路串联
用TLS 1.2的视角,把整个过程串起来大概是:
- 客户端发ClientHello,带上支持的TLS版本、随机数、密码套件列表。
- 服务器回ServerHello,选定版本和密码套件,附上自己的随机数。
- 服务器发Certificate(证书链),随后发送ServerKeyExchange(ECDHE参数),并用自己的私钥对这些参数签名。
- 客户端验证证书和签名,然后发ClientKeyExchange,把自己的ECDHE临时公钥发给服务器。
- 双方各自用“自己的临时私钥+对方的临时公钥”算出同一个共享密钥。
- 客户端发ChangeCipherSpec,表示“后面开始加密了”,再发一条加密的Finished消息。
- 服务器同样发ChangeCipherSpec和加密的Finished消息。
至此,双方完成确认,握手阶段结束,业务数据开始走加密通道。
4. 第三幕:暗号定好后,每一笔数据怎么被加密传输
握手完成之后,真正跑业务的阶段在TLS里叫记录层(Record Layer)。这一层做的事就是把HTTP报文切开、加密、加上完整性校验,再交给TCP发送。
4.1 对称加密负责“不让看”
握手阶段协商出来的会话密钥,最终会派生出一堆用于实际加密的子密钥。这些密钥配合对称加密算法(常见的有AES-GCM、ChaCha20-Poly1305)对HTTP报文进行加密。由于对称加密速度快,即使每个请求都要加密解密,性能损耗也完全可接受。
4.2 认证加密负责“不让改”
现代TLS使用的加密模式基本都带认证标签,比如AES-GCM里的GMAC。它的作用是让接收方不仅能解密,还能验证数据在传输途中有没有被篡改。加密和完整性校验一并完成,这类算法统称AEAD(带关联数据的认证加密)。
上面两点合起来回答了一个常见疑问:HTTPS到底防不防中间人篡改?答案很明确,防。攻击者可以截获密文,但没有会话密钥,既解不开也改不了——任何篡改都会导致接收方验签失败,连接直接中断。
4.3 会话恢复:为什么有时候握手很快
你可能会想,既然握手这么复杂,为什么平时访问网站感觉毫不费力?因为TLS有会话恢复机制。服务器会发一个加密的会话票据(Session Ticket)给客户端,客户端下次连接时可以直接带着票据恢复上一次的会话密钥状态,省去完整的握手过程,体验上几乎无感。
我在压测某HTTPS服务时发现,短连接场景下如果每次都走完整握手,TLS握手的CPU开销占比能到整体CPU的两三成。开启会话恢复后,这个数字显著下降。线上服务建议优先开启会话票据机制。
5. 边界认知:HTTPS行为大赏里那些“管不到”的环节
看了这么多HTTPS“管得住”的事,也必须聊聊它的边界。很多非技术同事以为:“上了HTTPS,网站就绝对安全了。”这其实是个危险的误解。
5.1 HTTPS保护的仅限于传输通道
HTTPS保证的是你的数据从浏览器到服务器这一路上的机密性和完整性。但这条路之外的事,它管不了:
- DNS解析阶段:浏览器解析域名时走的还是DNS查询,这一环本身不在HTTPS的保护范围内,DNS劫持依然可能发生。
- SNI泄露:TLS握手时为了路由到正确证书,客户端会明文发送服务器名称(SNI字段),这部分理论上可以被监听者看到访问的是哪个域名。
- 客户端环境:如果设备本身中了病毒,或者浏览器被植入了恶意插件,HTTPS保护不了终端内部的行为。
- 服务器端风险:服务器自身的配置漏洞、代码漏洞、运维疏漏,同样不在HTTPS的射程内。
5.2 “绿锁”不等于“好站点”
证书能证明“这个域名确实是某组织在运营”,但证明不了“这个组织是善意的”。钓鱼网站一样可以申请到合法的HTTPS证书。所以,看到地址栏的小锁标志,只说明数据传输通道是安全的,不代表网页内容本身值得信赖。这句话我在自己的团队里反复强调过很多次。
6. 抓包实战:如何解密自己的HTTPS流量,以及几个典型报错复盘
纸上谈兵再多,不如亲手抓一次包。最后一章讲讲我在实际排障时是怎么把HTTPS流量解密的,以及遇到过的几类典型行为异常。
6.1 用SSLKEYLOGFILE解密TLS流量
很多同学问:HTTPS流量不是加密的吗?抓包软件为什么能看到明文?答案是:抓包软件并不破解加密,而是通过读浏览器或程序导出的密钥日志文件,还原出会话密钥,再用它解密流量。
操作步骤很简单:
- 设置环境变量,指定密钥日志文件路径:
export SSLKEYLOGFILE=~/.ssl-key.log用支持该变量的浏览器或curl发起HTTPS请求。浏览器需要配置对应的环境变量启动,curl则直接受环境变量控制。
在Wireshark里打开抓包文件,在设置中填入相同的密钥日志文件路径,就能看到解密后的HTTP请求和响应。
需要注意的是,这只能解你自己能控制密钥的流量。抓到别人的HTTPS流量想靠这招解开,基本不可能——这也是HTTPS加密的意义所在。
6.2 定位一次“握手卡顿”问题
回到文章开头的那个排障场景。某同事的系统频繁出现偶发超时,我通过上述方法抓到解密后的流量后,发现症结不在业务层,而是TLS握手阶段的重传和乱序。最终定位到是服务器TCP队列溢出导致部分握手指针丢失,调整内核参数后问题消失。如果没有解密能力,光看一堆密文,根本不可能在几分钟内锁定问题。
6.3 常见的三类证书行为异常
我接手过不少证书相关的“疑难杂症”,总结下来最常见的三种行为异常:
| 现象 | 常见原因 | 处理建议 |
|---|---|---|
| 证书过期 | 有效期到了没续期 | 配置证书过期监控,提前30天提醒 |
| 证书链不完整 | 只部署了服务器证书 | 服务器证书与中间证书一并配置 |
| 混合内容被拦截 | HTTPS页面里引用了HTTP资源 | 全站资源统一走HTTPS,必要时用页面升级策略补漏 |
这仨问题我在不同项目里至少各遇到过一次。每次解决完我都会感叹一句:HTTPS的“行为大赏”看着复杂,但把它拆成“一次身份验证、一次密钥协商、一套加密记录层”三条主线之后,排障思路会清晰得多。
我自己在使用中最大的体会是:理解HTTPS加密过程,真正的价值不在于能背出多少术语,而在于遇到问题时能快速判断——问题出在哪一层、应该看哪个字段、该往哪个方向排查。如果这篇能帮你建立这样一条认知链路,那就值了。