453 lines
27 KiB
Markdown
453 lines
27 KiB
Markdown
---
|
||
title: HTTPS 握手里的 RSA 和 ECDHE,到底差在哪?(应用层)
|
||
description: 对比 TLS 握手中 RSA 密钥交换与 ECDHE 密钥交换的核心差异,讲清前向安全、密码套件命名、TLS 1.3 变化及面试要点。
|
||
category: 计算机基础
|
||
tag:
|
||
- 计算机网络
|
||
head:
|
||
- - meta
|
||
- name: keywords
|
||
content: HTTPS,RSA,ECDHE,TLS,握手,前向安全,密钥交换,密码套件,TLS 1.3,PreMasterSecret
|
||
---
|
||
|
||
很多人第一次学 HTTPS,脑子里会留下一个很粗的印象:
|
||
|
||
**HTTPS = HTTP + 加密,加密 = RSA。所以,HTTPS = RSA 加密。**
|
||
|
||
这个理解不是凭空来的。早期很多 HTTPS 部署确实大量使用 RSA 相关的密码套件,很多入门讲解也喜欢拿 RSA 举例。
|
||
|
||
但严格说,HTTPS 从来不等于 RSA 加密。即使在 TLS 1.0、TLS 1.1 时代,RSA 也只是可选方案之一,协议里还存在 DHE 这类密钥交换方式。到了 TLS 1.3,静态 RSA 密钥交换已经被移除,RSA 更多出现在证书签名、身份认证这类位置。
|
||
|
||
所以,这篇文章真正要对比的不是“RSA 和 ECDHE 谁更高级”。
|
||
|
||
**RSA 握手里,会话密钥材料是客户端生成后加密发给服务端;ECDHE 握手里,会话密钥材料不是直接传过去的,而是客户端和服务端各自算出来的。**
|
||
|
||
这篇文章主要回答几个问题:
|
||
|
||
1. HTTPS 为什么不等于 RSA 加密?
|
||
2. RSA 握手和 ECDHE 握手的会话密钥材料分别是怎么来的?
|
||
3. ECDHE 为什么能提供前向安全性?
|
||
4. TLS 1.3 为什么移除静态 RSA 密钥交换?
|
||
|
||
把这些问题讲清楚了,`PreMasterSecret`、`Server Key Exchange`、前向安全、TLS 1.3 为什么移除静态 RSA,后面都能顺着理解。
|
||
|
||

|
||
|
||
## TLS 握手的两个核心问题
|
||
|
||
HTTPS 仍然基于 HTTP,也仍然依赖 TCP。区别在于,HTTP 报文不会直接裸跑在 TCP 之上,而是先经过 TLS 完成身份认证、密钥协商和加密保护。
|
||
|
||
握手完成后,真正保护业务数据的通常是 AES-GCM 这类对称加密算法,而不是拿 RSA 去加密完整的请求和响应。
|
||
|
||
这里有两个问题。
|
||
|
||
**第一个问题:浏览器和服务器需要协商出一份会话密钥。**
|
||
|
||
后面传输 HTTP 请求、Cookie、响应体时,就用这份会话密钥做对称加密。对称加密更适合处理大量数据;非对称加密计算成本高,一般不拿来直接加密完整网页内容。
|
||
|
||
**第二个问题:浏览器需要确认对面真的是目标网站。**
|
||
|
||
如果只是“服务器发一个公钥给浏览器”,那中间人也可以发自己的公钥。浏览器以为那是目标网站的公钥,后面就把秘密信息加密给了攻击者。证书、CA、数字签名解决的是这件事:证明这个公钥确实和这个域名绑定,而不是路上某个人塞进来的。
|
||
|
||
RSA 握手和 ECDHE 握手都会面对这两个问题。只是它们解决“会话密钥怎么来”的方式不同。
|
||
|
||
## RSA 握手:密钥材料加密发送
|
||
|
||
### 完整握手流程
|
||
|
||
先看 TLS 1.2 里的 RSA 密钥交换。
|
||
|
||
浏览器先发 `ClientHello`。这里面会带上客户端支持的 TLS 版本、支持的密码套件、一个随机数 `Client Random`。
|
||
|
||
服务器收到之后,回 `ServerHello`,选定 TLS 版本和密码套件,也给出一个随机数 `Server Random`,然后把自己的证书发给客户端。
|
||
|
||
到这里,客户端拿到了服务器证书。它会验证证书链、域名、有效期、签名这些信息。证书验证通过后,客户端就从证书里取出服务器的 RSA 公钥。
|
||
|
||
接下来是关键步骤:客户端生成一个新的随机值,也就是 `PreMasterSecret`。在 TLS 1.2 的 RSA 密钥交换里,这个值是 **48 字节**。客户端会用服务器证书里的 RSA 公钥加密 `PreMasterSecret`,再把加密结果放进 `Client Key Exchange` 发给服务器。
|
||
|
||
服务器收到后,用自己的 RSA 私钥解密,拿到同一份 `PreMasterSecret`。
|
||
|
||
这时,客户端和服务端手里都有三份材料:
|
||
|
||
```text
|
||
Client Random
|
||
Server Random
|
||
PreMasterSecret
|
||
```
|
||
|
||
双方再根据这三份材料派生出 `Master Secret`,后续的会话密钥也会从这里继续派生出来。真正传 HTTP 请求和响应时,用的是这些派生出来的对称密钥。
|
||
|
||
用一句话压缩:
|
||
|
||
**RSA 握手的会话密钥材料,是客户端生成后“包起来”寄给服务器的。**
|
||
|
||
这里的“包起来”,靠的就是服务器 RSA 公钥。只有持有对应 RSA 私钥的服务器,才能拆开这个包。
|
||
|
||
看起来挺合理。客户端生成秘密,服务器私钥解密,双方得到同一份材料,再结合两个随机数派生出后续会话密钥。
|
||
|
||
但问题也在这里。
|
||
|
||
### 没有前向安全:长期私钥太值钱
|
||
|
||
假设攻击者今天抓到了一段 HTTPS 流量,但当时没有服务器私钥,所以看不懂里面的内容。这时他可以先把流量保存下来。
|
||
|
||
一年后,如果服务器 RSA 私钥泄漏了,会发生什么?
|
||
|
||
在 RSA 密钥交换里,客户端当年发出的 `PreMasterSecret` 是用服务器 RSA 公钥加密的。如果攻击者完整捕获了握手阶段的明文随机数,也就是 `Client Random`、`Server Random`,同时保存了加密后的 `PreMasterSecret`,再结合后来泄漏的服务器私钥,就可能解开当时的 `PreMasterSecret`,继续派生出那次连接用过的会话密钥。
|
||
|
||
旧数据就有机会被翻出来。
|
||
|
||
这里要注意条件:不是“只要私钥泄漏,所有历史流量必然能解”。攻击者至少得拿到足够完整的握手数据和应用数据。如果只有单向片段,或者握手日志不完整,即使有私钥,也未必能把那次会话还原出来。
|
||
|
||
但从安全设计上看,这个风险已经足够麻烦。长期私钥一旦变成打开历史流量的总钥匙,它的影响就不再只覆盖未来连接,也会波及过去已经发生过的通信。
|
||
|
||
这里批评的不是 RSA 算法本身“不能用”。RSA 仍然可以用于签名认证,也可以出现在证书体系里。问题出在“用长期不变的服务器私钥去解密历史握手里的密钥材料”。
|
||
|
||
服务器私钥一旦泄漏,代价太大。
|
||
|
||

|
||
|
||
### 另一个历史包袱:填充预言机攻击
|
||
|
||
RSA 密钥交换还有一个工程层面的麻烦:`PreMasterSecret` 不是直接裸加密,而是按 RSAES-PKCS1-v1_5 这类格式封装后再加密。
|
||
|
||
这个细节曾经引出过 Bleichenbacher 这类填充预言机攻击。
|
||
|
||
它的大致思路是:攻击者不一定要马上拿到服务器私钥,而是反复构造不同的密文发给服务器,观察服务器对“填充错误、版本错误、长度错误”的处理差异。如果服务端在错误码、响应时间、日志行为、连接关闭方式上露出差别,攻击者就可能一点点逼近明文。
|
||
|
||
这类攻击麻烦的地方在于,它不是单纯的数学问题,而是实现问题。
|
||
|
||
TLS 1.2 对这类情况做过防御要求:服务端即使解密失败,也不要把具体失败原因暴露出去,而是继续用随机值走完整个流程,避免攻击者通过差异行为判断密文是否接近正确格式。
|
||
|
||
可规范要求不等于实现可靠。2017 年的 ROBOT 攻击再次说明,一些服务端仍然可能因为细小的行为差异暴露出 RSA 解密 oracle。错误码、耗时、日志、分支路径,只要有一处表现不一致,都可能变成侧信道。
|
||
|
||
所以,静态 RSA 密钥交换被淘汰,不只是因为它没有前向安全,也因为它把太多风险压到了实现细节上。
|
||
|
||
### 能否被降级回 RSA?
|
||
|
||
这里还要补一个容易误解的点。
|
||
|
||
TLS 1.2 里,客户端会在 `ClientHello` 里带上自己支持的密码套件列表,服务端从里面选一个双方都支持的套件。理论上,如果服务端仍然开放 `TLS_RSA_*` 这类静态 RSA 密钥交换套件,老客户端就可能继续用 RSA 握手。
|
||
|
||
但这不等于“中间人随便把 ClientHello 里的 ECDHE 删掉,就能让连接悄悄降级到 RSA”。握手最后的 `Finished` 会校验握手 transcript,简单篡改 `ClientHello` 通常会导致校验失败,连接建立不起来。
|
||
|
||
历史上确实发生过降级相关攻击,比如 FREAK 和 Logjam。它们利用的是当时一些客户端、服务端仍然支持出口级弱密码套件,再结合实现和配置问题,把连接压到更弱的 RSA_EXPORT 或 DHE_EXPORT 路径上,而不是“随便删掉 ECDHE 就能静默成功”。TLS 1.3 在 `ServerHello.random` 里加入降级保护值,也是在提醒我们:协议本身一直在补这类历史攻击面。
|
||
|
||
真正需要关注的是服务端配置本身:如果已经不需要兼容很老的客户端,就应该关闭静态 RSA 密钥交换套件,只保留支持前向安全的套件。否则,环境里仍然可能存在客户端或错误配置走到 RSA 握手。
|
||
|
||
这也是排查 TLS 配置时要看密码套件实际协商结果的原因。只看“服务器支持 ECDHE”不够,还要看它是否同时保留了 `TLS_RSA_*` 这类旧套件。
|
||
|
||
## ECDHE 握手:密钥材料双方协商
|
||
|
||
### DH 的核心思路
|
||
|
||
ECDHE 里的 `DHE` 来自 Diffie-Hellman Ephemeral,意思是临时 Diffie-Hellman。前面的 `EC` 是 Elliptic Curve,表示基于椭圆曲线。
|
||
|
||
别被名字吓住。先不看椭圆曲线,先看 DH 想解决什么问题。
|
||
|
||
DH 的目标很有意思:通信双方不直接传输共享秘密,却能各自算出同一个共享秘密。
|
||
|
||
可以粗略理解成这样:
|
||
|
||
客户端生成一个临时私钥,只留在本地,再算出一个临时公钥发给服务器。服务器也生成一个临时私钥,只留在本地,再算出一个临时公钥发给客户端。
|
||
|
||
双方交换的都是公钥。攻击者在网络里能看到这些公钥,但看不到双方各自的临时私钥。
|
||
|
||
接着,客户端用“自己的临时私钥 + 服务器临时公钥”算出共享秘密;服务器用“自己的临时私钥 + 客户端临时公钥”也算出同一个共享秘密。
|
||
|
||
共享秘密没有在网络上传输过。
|
||
|
||
ECDHE 只是把这个过程放到椭圆曲线体系里做。椭圆曲线的数学理论更抽象,但在同等安全强度下,它通常能用更短的密钥达到相近的安全级别,运算和传输成本也比传统有限域 DHE 更低。对理解 TLS 握手来说,先记住一句话就够了:
|
||
|
||
**ECDHE 的会话密钥材料不是某一方生成后发给另一方,而是双方通过临时密钥协商出来的。**
|
||
|
||
### 完整握手流程
|
||
|
||
再看 TLS 1.2 里常见的 `ECDHE_RSA` 握手。
|
||
|
||
客户端还是先发 `ClientHello`,里面有 TLS 版本、支持的密码套件、`Client Random`。服务器回 `ServerHello`,选择一个密码套件,比如:
|
||
|
||
```text
|
||
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
||
```
|
||
|
||
这个密码套件名要拆开看,不能看到 RSA 就以为它还在用 RSA 加密会话密钥。
|
||
|
||
- `ECDHE` 表示密钥交换方式。
|
||
- `RSA` 表示认证签名方式。
|
||
- `AES_256_GCM` 表示后续记录数据使用 AES,密钥长度 256 位,模式是 GCM。
|
||
- `SHA384` 指定 TLS 1.2 PRF 和 `Finished` 消息使用的哈希算法。
|
||
|
||
GCM 本身已经提供记录层的完整性保护,所以这里的 `SHA384` 不再表示记录层 MAC,而是主要参与握手阶段的密钥派生和验证。
|
||
|
||
服务端接着发证书。以 `ECDHE_RSA` 为例,证书里的 RSA 公钥主要用于验证服务端签名,而不是让客户端拿它加密 `PreMasterSecret`。
|
||
|
||
然后,ECDHE 和 RSA 握手开始分叉。
|
||
|
||
在 ECDHE 握手里,服务端会发送 `Server Key Exchange`。这个消息里会包含服务端选择的椭圆曲线参数,以及服务端临时 ECDHE 公钥。
|
||
|
||
**问题来了:客户端怎么知道这份临时 ECDHE 公钥没有被中间人换掉?**
|
||
|
||
**答案是签名。**
|
||
|
||
服务端会用证书对应的私钥,对握手参数做签名。客户端收到后,用证书里的公钥验证签名。如果签名验证通过,客户端就能确认:这份临时 ECDHE 公钥确实来自持有证书私钥的服务器,不是路上被人替换的。
|
||
|
||
随后客户端也生成自己的临时 ECDHE 私钥和公钥,把客户端临时公钥通过 `Client Key Exchange` 发给服务器。
|
||
|
||
到这一步,双方都有了计算共享秘密需要的材料。
|
||
|
||
客户端手里有:
|
||
|
||
```text
|
||
客户端临时私钥
|
||
服务端临时公钥
|
||
Client Random
|
||
Server Random
|
||
```
|
||
|
||
服务端手里有:
|
||
|
||
```text
|
||
服务端临时私钥
|
||
客户端临时公钥
|
||
Client Random
|
||
Server Random
|
||
```
|
||
|
||
两边各自计算出同一个共享秘密,再派生出后续使用的会话密钥。
|
||
|
||
这里再强调一次:
|
||
|
||
**ECDHE_RSA 里的 RSA,不是用来加密传输会话密钥的。它负责证明“这份 ECDHE 临时参数确实是服务器发的”。**
|
||
|
||
这也是很多人看到密码套件名字后最容易误会的地方。
|
||
|
||

|
||
|
||
### 密码套件名怎么读
|
||
|
||
TLS 1.2 的密码套件名字通常可以按这条线拆:
|
||
|
||
```text
|
||
TLS_密钥交换算法_认证算法_WITH_对称加密算法_哈希算法
|
||
```
|
||
|
||
例如:
|
||
|
||
```text
|
||
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||
```
|
||
|
||
可以拆成:
|
||
|
||
```text
|
||
ECDHE:密钥交换
|
||
RSA:身份认证,也就是服务端签名
|
||
AES_128_GCM:后续记录层加密算法
|
||
SHA256:TLS 1.2 PRF 和 Finished 消息使用的哈希算法;如果是 GCM 套件,它不再充当记录层 MAC
|
||
```
|
||
|
||
再看另一个:
|
||
|
||
```text
|
||
TLS_RSA_WITH_AES_128_GCM_SHA256
|
||
```
|
||
|
||
这里的 `RSA` 出现在 `WITH` 前面,而且没有 `ECDHE`,表示密钥交换和身份认证都和 RSA 绑定。这类就是典型的静态 RSA 密钥交换套件。
|
||
|
||
到了 TLS 1.3,密码套件命名变了,比如:
|
||
|
||
```text
|
||
TLS_AES_128_GCM_SHA256
|
||
```
|
||
|
||
你会发现,它不再把密钥交换和认证方式写进密码套件名里。TLS 1.3 把这些信息拆到其他扩展和握手消息中,密码套件名主要描述记录层 AEAD 算法和 HKDF 使用的哈希算法。
|
||
|
||
所以,看到 TLS 1.3 的 `TLS_AES_128_GCM_SHA256`,不要误以为它“没有密钥交换”。密钥交换还在,只是不用 TLS 1.2 那套命名方式写出来了。
|
||
|
||

|
||
|
||
## 前向安全与性能代价
|
||
|
||
### ECDHE 为什么有前向安全
|
||
|
||
关键在 `E`,也就是 `Ephemeral`,临时。
|
||
|
||
ECDHE 握手里的私钥不是服务器证书那把长期私钥,而是握手过程中使用的临时私钥。连接结束后,正常情况下不应该再依赖这份临时材料。
|
||
|
||
这带来的结果是:攻击者今天抓包,未来某天拿到了服务器证书私钥,也不能仅靠这把长期私钥还原过去每次握手里的临时共享秘密。因为当时真正参与密钥协商的是那次握手里的 ECDHE 临时私钥,而不是证书私钥。
|
||
|
||
证书私钥在这里更像“签字笔”,不是“保险柜钥匙”。
|
||
|
||
RSA 密钥交换里,服务器私钥可以直接打开客户端发来的 `PreMasterSecret`;ECDHE 里,服务器私钥只是给临时参数签名,证明身份。它不直接参与每次连接共享秘密的计算。
|
||
|
||
这个角色变化,决定了两者在历史流量保护上的差异。
|
||
|
||

|
||
|
||
不过,前向安全不是免死金牌。
|
||
|
||
如果服务端随机数质量很差,临时私钥被日志记录下来,或者实现里出现内存泄漏,ECDHE 也救不了你。工程实现里,为了降低握手成本,部分实现还可能短时间复用临时 DH/ECDH 私密材料:有限域 DH 场景常说“指数复用”,ECDH 场景更常说“临时私钥/标量复用”。如果复用时间过长,前向安全的粒度就会变粗。
|
||
|
||
还有一类风险来自参数校验。比如服务端没有正确校验客户端发来的椭圆曲线点是否在合法曲线上,就可能给无效曲线攻击留下空间。正常开发者不一定会直接写这层代码,但它提醒我们:密码学协议不只是“选对算法”就结束了,TLS 库实现和配置同样重要。
|
||
|
||
### 会话恢复的影响
|
||
|
||
还有一个容易被忽略的点:**会话恢复。**
|
||
|
||
完整 ECDHE 握手要做临时密钥协商,成本不低。为了减少握手开销,TLS 支持会话恢复。客户端下次访问同一个站点时,可以尝试复用之前协商过的会话状态,避免每次都完整走一遍握手。
|
||
|
||
问题在于,会话恢复也有自己的安全边界。
|
||
|
||
以 TLS 1.2 的会话票据为例,服务端会用一把票据加密密钥保护会话状态,客户端后续带着票据回来,服务端解开票据后恢复会话。如果这把票据加密密钥长期不轮换,一旦它泄漏,攻击者就可能解开过去收集到的票据,并进一步还原相关恢复会话的密钥材料。
|
||
|
||
这时,前向安全的窗口就不再是“一次连接”,而会被拉长到“票据加密密钥的生命周期”。
|
||
|
||
所以线上配置不能只看“是否启用了 ECDHE”。会话票据密钥怎么生成、怎么轮换、是否在多台机器间共享、泄漏后影响多大,也要算进去。
|
||
|
||
### 性能不是免费的
|
||
|
||
ECDHE 带来了前向安全,但它也有成本。
|
||
|
||
RSA 密钥交换的主路径,是服务端用长期 RSA 私钥解开客户端发来的 `PreMasterSecret`。ECDHE_RSA 则需要完成临时 ECDH 协商,还要对服务端临时参数做签名。
|
||
|
||
对高并发服务来说,TLS 握手会消耗 CPU,尤其是短连接多、会话恢复命中率低的时候。
|
||
|
||
这里不能简单写成“ECDHE 一定比 RSA 慢”。实际开销取决于 RSA 密钥长度、椭圆曲线选择、签名算法、TLS 库实现、CPU 指令集、会话恢复命中率等因素。比如 X25519、P-256、RSA 2048、RSA 3072 在不同 CPU 和不同 TLS 库上的表现都不一样。
|
||
|
||
如果真要判断成本,最靠谱的方法不是引用别人的固定数字,而是在目标机器上压测。至少要区分三件事:
|
||
|
||
```text
|
||
1. 单次密码学操作耗时
|
||
2. 完整 TLS 握手耗时
|
||
3. 业务请求端到端耗时
|
||
```
|
||
|
||
第一项可以用 `openssl speed` 粗看数量级,比如测试 RSA、ECDH、X25519 的运算能力;第二项要看 TLS 库和服务端配置;第三项还会受网络、连接复用、应用逻辑影响。
|
||
|
||
所以线上不会只靠“换成 ECDHE”解决所有问题。更常见的做法是配合 TLS 1.3、会话恢复、合理的证书算法和曲线选择,必要时再用硬件加速。
|
||
|
||
安全性和性能不是二选一,但也不能假装没有成本。
|
||
|
||
## TLS 1.3 的变化
|
||
|
||
如果只看 TLS 1.2,RSA 和 ECDHE 可以作为两种密钥交换方式来对比。
|
||
|
||
但到了 TLS 1.3,静态 RSA 密钥交换已经被移除,握手结构也改了。
|
||
|
||
TLS 1.2 完整握手通常需要 2 个 RTT。客户端先发 `ClientHello`,服务端回 `ServerHello`、证书和相关握手消息,客户端再发密钥交换和 `Finished`,服务端最后回 `Finished`。
|
||
|
||
TLS 1.3 则把密钥交换参数提前放进 `ClientHello` 的 `key_share`。服务端第一轮响应就能返回自己的 `key_share`,完整握手通常压到 1 个 RTT。
|
||
|
||
2 RTT 变 1 RTT 能省多少毫秒,取决于网络环境。同机房可能只是几毫秒;跨地域、移动网络、高丢包场景下,少一个 RTT 才更容易被感知。
|
||
|
||
不过,TLS 1.3 也不是任何情况下都稳稳 1 RTT。如果客户端带的 `key_share` 和服务端支持的曲线不匹配,服务端会返回 `HelloRetryRequest`,要求客户端换一组参数再来一次。这时握手可能重新接近 2 RTT。
|
||
|
||
所以生产环境里,客户端和服务端对常见密钥协商组的支持要尽量对齐,比如 `X25519`、`secp256r1` 这类常见选择。否则 TLS 1.3 的 1 RTT 优势可能打折。
|
||
|
||

|
||
|
||
至于后量子混合密钥交换、0-RTT、PSK-only、mTLS,这些都属于另一条线,本文不展开。
|
||
|
||
## RSA vs ECDHE 核心差异速查
|
||
|
||
放到一起看,差异就很清楚了。
|
||
|
||
| 对比项 | RSA 密钥交换 | ECDHE 密钥交换 |
|
||
| ------------------ | ------------------------------------------------------- | ------------------------------------------------------ |
|
||
| 常见版本背景 | TLS 1.2 及更早版本可见 | TLS 1.2 常见,TLS 1.3 延续临时密钥协商方向 |
|
||
| 会话密钥材料怎么来 | 客户端生成 `PreMasterSecret`,用服务器 RSA 公钥加密发送 | 双方各自生成临时密钥对,通过 ECDHE 算出共享秘密 |
|
||
| 服务器私钥的作用 | 解密客户端发来的 `PreMasterSecret` | 对临时 ECDHE 参数签名,证明参数来自真实服务端 |
|
||
| 网络上传了什么 | 加密后的 `PreMasterSecret` | 双方临时公钥和签名后的参数 |
|
||
| 是否支持前向安全 | 不支持 | 支持,前提是临时密钥正确生成、使用后不再保留 |
|
||
| 私钥泄漏后的影响 | 在握手数据完整捕获的情况下,历史流量可能被解密 | 仅靠证书私钥,通常无法解开历史流量 |
|
||
| 典型问题 | 长期私钥价值过高,存在 PKCS#1 v1.5 填充预言机历史包袱 | 握手有额外计算成本,参数校验和临时密钥管理依赖实现质量 |
|
||
| TLS 1.3 情况 | 静态 RSA 密钥交换已移除 | 临时密钥协商成为主线 |
|
||
|
||

|
||
|
||
如果你要在面试里快速讲,可以这样说:
|
||
|
||
**RSA 握手是“客户端生成秘密,用服务器公钥加密发过去”;ECDHE 握手是“双方交换临时公钥,各自算出同一个秘密”。RSA 的服务器私钥能解历史握手材料,所以没有前向安全;ECDHE 的证书私钥只做签名认证,不直接解会话秘密,所以更适合现代 HTTPS。**
|
||
|
||
这段就够用了。
|
||
|
||
### 常见误读:ECDHE_RSA 不是两种算法都加密
|
||
|
||
再单独说一下 `ECDHE_RSA`,因为这个名字太容易让人误读。
|
||
|
||
很多人看到:
|
||
|
||
```text
|
||
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
||
```
|
||
|
||
第一反应是:是不是先做一轮 ECDHE 运算,再做一轮 RSA 加密?
|
||
|
||
不是。
|
||
|
||
在这个密码套件里:
|
||
|
||
密钥交换用 ECDHE;
|
||
身份认证用 RSA 签名;
|
||
后续数据加密用 AES-256-GCM;
|
||
相关哈希使用 SHA384。
|
||
|
||
这也解释了为什么“HTTPS 还在用 RSA”这句话要小心说。
|
||
|
||
用 RSA 做证书签名,和用 RSA 做密钥交换,是两件事。
|
||
|
||
前者在现代 HTTPS 里仍然常见,后者已经不适合作为现代 TLS 的主线。
|
||
|
||
### RSA 在现代 HTTPS 里的实际角色
|
||
|
||
学习 HTTPS 握手时,很多入门资料喜欢用一句话概括:
|
||
|
||
非对称加密交换对称密钥。
|
||
|
||
这句话在入门阶段有帮助,但不够准确。它更像是在描述早期 RSA 密钥交换的思路。
|
||
|
||
到了 ECDHE,密钥不是简单“加密后传输”,而是双方协商出来的。到了 TLS 1.3,密钥交换、身份认证、记录层加密的边界更清楚:临时密钥协商负责生成共享秘密,证书负责身份认证,对称加密负责保护后续应用数据。
|
||
|
||
更准确的说法应该是:
|
||
|
||
HTTPS 的业务数据通常用对称密钥加密;TLS 握手负责协商这份密钥并验证身份。RSA 可以参与身份认证,也曾经可以参与密钥交换;ECDHE 负责临时密钥协商,能避免历史会话因为未来证书私钥泄漏而直接暴露。
|
||
|
||
如果把这几件事混在一起,就很容易得出错误结论:看到 RSA 就以为它在加密会话密钥,看到 ECDHE_RSA 就以为两种算法都在做加密。
|
||
|
||
事实不是这样。
|
||
|
||
## 用一次完整请求串起来
|
||
|
||
浏览器访问一个 HTTPS 网站时,TCP 连接先建立起来。接着 TLS 握手开始。
|
||
|
||
如果是 TLS 1.2 的 RSA 密钥交换,客户端验证证书后,生成 48 字节的 `PreMasterSecret`,用服务器证书里的 RSA 公钥加密发给服务器。服务器用 RSA 私钥解密,双方再结合两个随机数派生会话密钥。
|
||
|
||
如果是 TLS 1.2 的 ECDHE_RSA,服务器发证书后,还会发 `Server Key Exchange`,里面带着临时 ECDHE 公钥和签名。客户端验证签名后,也生成自己的临时 ECDHE 公钥发回去。双方不传输最终共享秘密,而是各自算出同一个共享秘密,再派生会话密钥。
|
||
|
||
这两个流程看起来只差了几个握手消息,安全性质却差很多。
|
||
|
||
RSA 密钥交换的问题是历史包袱太重:长期私钥一旦泄漏,过去保存下来的流量也可能遭殃;再加上 PKCS#1 v1.5 填充预言机这类实现风险,它已经不适合作为现代 TLS 密钥交换方案。
|
||
|
||
ECDHE 把每次连接的密钥协商换成临时过程,让服务器长期私钥不再成为打开历史流量的钥匙。它也有计算成本,也依赖正确实现和配置,但方向更符合现代 HTTPS 的安全要求。
|
||
|
||
这篇文章只聚焦一个问题:**RSA 密钥交换和 ECDHE 密钥交换到底差在哪**。如果继续往下讲,还可以展开 TLS 1.3 的 0-RTT、PSK、会话票据轮换、mTLS、证书透明、后量子迁移,这些都值得单独写。
|
||
|
||
所以,面试里问“RSA 和 ECDHE 握手有什么区别”,不要只回答“一个不支持前向安全,一个支持前向安全”。
|
||
|
||
真正要讲的是:
|
||
|
||
**RSA 是把秘密加密送过去;ECDHE 是双方临时协商出来。**
|
||
|
||
把这句话讲透,后面的 `PreMasterSecret`、`Server Key Exchange`、前向安全、TLS 1.3 为什么移除静态 RSA,就都能顺着讲下去了。
|
||
|
||
## 面试怎么回答:HTTPS 握手里的 RSA 和 ECDHE,到底差在哪?
|
||
|
||
RSA 和 ECDHE 的核心区别在于:**会话密钥材料是“传过去的”,还是“协商出来的”**。
|
||
|
||
在 TLS 1.2 的静态 RSA 握手里,客户端生成 `PreMasterSecret`,用服务器证书里的 RSA 公钥加密后发给服务端,服务端再用 RSA 私钥解密。问题是,如果攻击者保存了当年的握手流量,后来服务器私钥又泄漏,就可能回头解出历史会话密钥,所以它没有前向安全。
|
||
|
||
ECDHE 不直接传输共享秘密。客户端和服务端各自生成临时密钥对,交换临时公钥后,双方本地算出同一个共享秘密。服务器证书私钥主要用于签名认证,证明临时参数没被中间人替换,而不是用来解密会话密钥。
|
||
|
||
所以一句话总结:**RSA 是客户端把秘密加密送过去;ECDHE 是双方用临时密钥协商出秘密。ECDHE 支持前向安全,也因此成为现代 HTTPS 的主流方向。**
|