HTTPS
HTTPS 在 HTTP 与 TCP 层之间加入了 SSL/TLS
协议,可以很好的解决了上述的风险:
- 信息加密:混合加密,防止窃听。
- 校验机制:摘要算法+数字签名,无法篡改通信内容。
- 身份证书:数字证书,防止伪造。
混合加密
-
对称加密:使用一个密钥,运算速度快,密钥必须保密,无法做到安全的密钥交换。
-
非对称加密:使用公钥和私钥,公钥可以任意分发而私钥保密,解决了密钥交换问题但速度慢。
-
混合加密:
-
在通信建立前:非对称加密的方式交换「会话秘钥」。
-
通信过程中使用对称加密的「会话密钥」加密明文数据。
-
摘要算法 + 数字签名
- 摘要算法(哈希函数):对内容计算出哈希值一起发送,对方收到再计算一遍,一致说明内容未篡改。
Why?
内容和哈希值一起被篡改,无法分辨
How?
- 数字签名:对内容的哈希值加密,私钥对信息加密,公钥解密。私钥是不可泄露的,如果公钥能正常解密出私钥加密的内容,就能证明这个消息是来源于持有私钥身份的人发送的。
数字证书
Why?
防止公钥是伪造的,被做了局。
How?
- 数字证书:第三方可信单位确保公钥的真实性
数字证书签发和验证流程
数字证书通常包含了:
- 公钥;
- 持有者信息;
- 证书认证机构(CA)的信息;
- CA 对这份文件的数字签名及使用的算法;
- 证书有效期;
- 还有一些其他额外信息;
CA 签发证书的过程:
- CA 会把持有者的公钥、用途、颁发者、有效时间等信息打成一个包, Hash 计算得到一个 Hash 值;
- CA 会使用自己的私钥将该 Hash 值加密,生成 Certificate Signature,也就是 CA 对证书做了签名;
- 最后将 Certificate Signature 添加在文件证书上,形成数字证书;
客户端校验服务端的数字证书的过程:
-
客户端会使用同样的 Hash 算法获取该证书的 Hash 值 H1;
-
通常浏览器和操作系统中集成了 CA 的公钥信息,公钥解密 Certificate Signature 内容,得到 Hash 值 H2 ;
-
最后比较 H1 和 H2,如果值相同,则为可信赖的证书,否则则认为证书不可信。
证书信任链
Why?
向 CA 申请的证书一般不是根证书签发的,而是由中间证书签发的
三级层级关系的证书的验证过程如下:
- 直到证书的签发机构,然后向 CA 请求该中间证书。
- 中间证书没有上级签发机构,说明它是根证书,也就是自签证书。软件会检查此证书有否已预载于根证书清单上,如果有,则可以利用根证书中的公钥去验证。
- 依次向下验证。
Root CA 为什么不直接颁发证书?
确保根证书的绝对安全性,将根证书隔离地越严格越好,不然根证书如果失守了,那么整个信任链都会有问题。
SSL/TLS 流程
-
ClientHello:
- 客户端支持的 TLS 协议版本,如 TLS 1.2 版本。
- 客户端生产的随机数(Client Random),后面用于生成「会话秘钥」条件之一。
- 客户端支持的密码套件列表,如 RSA 加密算法。
-
SeverHello
- 确认 TLS 协议版本,如果浏览器不支持,则关闭加密通信。
- 服务器生产的随机数(Server Random),也是后面用于生产「会话秘钥」条件之一。
- 确认的密码套件列表,「(密钥交换算法 + 签名算法) + 对称加密算法 + 摘要算法」。
- 服务器的数字证书,用户CA解密得到公钥。
-
客户端回应
-
首先通过浏览器或者操作系统中的 CA 公钥,确认服务器的数字证书的真实性。如果证书没有问题,客户端会从数字证书中取出服务器的公钥,然后使用它加密报文,向服务器发送如下信息:
- 一个随机数(pre-master key)。该随机数会被服务器公钥加密。
- 加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。
- 客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供服务端校验。
-
服务器和客户端有了这三个随机数(Client Random、Server Random、pre-master key),接着就用双方协商的加密算法,各自生成本次通信的「会话秘钥」。
-
-
服务器的最后回应
-
服务器收到客户端的第三个随机数(pre-master key)之后,通过协商的加密算法,计算出本次通信的「会话秘钥」。然后,向客户端发送最后的信息:
-
加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。
-
服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供客户端校验。
-
-
每一个「框」都是一个记录(record),记录是 TLS 收发数据的基本单位,类似于 TCP 里的 segment。多个记录可以组合成一个 TCP 包发送,所以通常经过「四个消息」就可以完成 TLS 握手,也就是需要 2个 RTT 的时延。
RSA 算法的缺陷
- 不支持前向保密。一旦服务端的私钥泄漏了,过去被第三方截获的所有 TLS 通讯密文都会被破解。
ECDHE 算法
离散对数
ECDHE 密钥协商算法是 DH 算法演进过来。DH 算法使用离散对数,是非对称加密算法, 因此它可以用于密钥交换
- 底数 a 和模数 p(大质数) 是离散对数的公共参数,b 是真数,i 是对数。
- 从左向右任意,右向左难
DH算法
- p、g:公开数
- a、b:私钥
- 公钥 A = G ^ a ( mod P );
- 公钥 B = G ^ b ( mod P );
- K = B ^ a ( mod P ) = G ^ b ( mod P ) ^ a ( mod P )
- K = A ^ b ( mod P ) = G ^ a ( mod P ) ^ b ( mod P )
- 得到了只有他两个人相互知道的数K
DHE算法
根据私钥生成的方式,DH 算法分为两种实现:
-
static DH 算法,已废弃:不具备前向安全性
- 有一方的私钥是静态的,服务端不变,客户端的私钥则是随机生成的。
- 由截获海量的密钥协商过程的数据,暴力破解出服务器的私钥。
-
DHE 算法
- 双方的私钥在每次密钥都是随机生成的、临时的,E 全称是 ephemeral(临时性的)。
ECDHE算法
Why?
DHE 算法由于计算性能不佳
How?
在 DHE 算法的基础上利用了 ECC 椭圆曲线特性,可以用更少的计算量计算出公钥,以及最终的会话密钥。
ECDHE握手过程
-
TLS 第一次握手
- 客户端「Client Hello」消息:TLS 版本号、支持的密码套件列表,以及生成的随机数(Client Random)
-
TLS 第二次握手
-
服务端「Server Hello」消息:确认的 TLS 版本号,随机数(Server Random),密码套件。
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- 密钥协商算法:ECDHE;
- 签名算法:RSA;
- 通信加密 AES 对称算法,密钥长度 256 位,分组模式是 GCM;
- 摘要算法:SHA384;
-
发送「Certificate」消息,会把证书也发给客户端。
-
发送「Server Key Exchange」消息
- 选择了名为 x25519 的椭圆曲线,相当于椭圆曲线基点 G 也定好了,这些都会公开给客户端;
- 生成随机数作为服务端椭圆曲线的私钥,保留到本地;
- 根据基点 G 和私钥计算出服务端的椭圆曲线公钥, RSA 对公钥做签名。公开给客户端。
-
「Server Hello Done」消息,打招呼完毕。
-
-
TLS 第三次握手
- 客户端生成随机数作为椭圆曲线的私钥,生成椭圆曲线公钥,「Client Key Exchange」消息发给服务端。
- 至此,双方都有对方的椭圆曲线公钥、自己的椭圆曲线私钥、椭圆曲线基点 G。双方都就计算出点(x,y),其中 x 坐标值双方都是一样的。
- 会话密钥,就是用「客户端随机数 + 服务端随机数 + x(ECDHE 算法算出的共享密钥) 」
- 算好会话密钥后,客户端会发一个「Change Cipher Spec」消息,告诉服务端后续改用对称算法加密通信。
- 发送「Encrypted Handshake Message」消息,把之前发送的数据做一个摘要,再用对称密钥加密一下,让服务端做个验证,验证下本次生成的对称密钥是否可以正常使用。
-
TLS 第四次握手
-
服务端也会有一个同样的操作,发「Change Cipher Spec」和「Encrypted Handshake Message」消息,如果双方都验证加密和解密没问题,那么握手正式完成。
-
客户端不用等服务端的最后一次 TLS 握手,就可以提前发出加密的 HTTP 数据,节省了一个消息的往返时间
-
HTTPS 的应用数据是如何保证完整性的?😡
-
消息被分割成多个较短的片段,然后分别对每个片段进行压缩。
-
加上消息认证码(MAC 值,这个是通过哈希算法生成的),这是为了保证完整性,并进行数据的认证。通过附加消息认证码的 MAC 值,可以识别出篡改。与此同时,为了防止重放攻击,在计算消息认证码时,还加上了片段的编码。
-
再加上消息认证码会一起通过对称密码进行加密。
-
再加上由数据类型、版本号、压缩后的长度组成的报头就是最终的报文数据。
SSL/TLS 1.2 需要 4 握手,需要 2 个 RTT 的时延,SSL/TLS 1.3 优化了过程,只需要 1 个 RTT 往返时延,也就是只需要 3 次握手。
HTTPS 如何优化
分析性能损耗
-
TLS 协议握手过程:2RTT延迟+性能损耗
- 对于 ECDHE 密钥协商算法,握手过程中会客户端和服务端都需要临时生成椭圆曲线公私钥;
- 客户端验证证书时,会访问 CA 获取 CRL 或者 OCSP,目的是验证服务器的证书是否有被吊销;
- 双方计算 Pre-Master,也就是对称加密密钥;
-
握手后的对称加密报文传输:主流的对称加密算法 AES、ChaCha20 性能不错,CPU 硬件级别优化
硬件优化
HTTPS 协议是计算密集型,而不是 I/O 密集型
选择可以支持 AES-NI 特性的 CPU,指令级别优化了 AES 算法
# 查看 CPU 是否支持 AES-NI 指令集
sort -u /proc/crypto | grep module | grep aes
module : aesni_intel
软件优化
-
软件升级:
- 将 Linux 内核从 2.x 升级到 4.x;
- 将 OpenSSL 从 1.0.1 升级到 1.1.1;
协议优化
-
密钥交换算法优化
-
TLS 1.2 版本 4 次握手,也就是要花费 2 RTT,安全性也不高。
-
TLS 1.3 版本,第 3 次握手后,第 4 次握手前,发送加密的应用数据,花费 1 RTT,安全性高。
- 椭圆曲线尽量选择 x25519 曲线,最快
-
-
对称加密算法:
- 对安全性不是特别高的要求,可以选用 AES_128_GCM,它比 AES_256_GCM 快一些
-
TLS 升级
-
把 TLS 1.2 升级成 TLS 1.3,把 Hello 和公钥交换这两个消息合并成了一个消息,客户端在 Client Hello 消息里带上了支持的椭圆曲线,以及这些椭圆曲线对应的公钥。
-
TLS1.3 对于密钥交换算法,废除了不支持前向安全性的 RSA 和 DH 算法,只支持 ECDHE 算法。
-
对于对称加密和签名算法,只支持目前最安全的几个密码套件,比如 openssl 中仅支持下面 5 种密码套件:
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256
- TLS_AES_128_GCM_SHA256
- TLS_AES_128_CCM_8_SHA256
- TLS_AES_128_CCM_SHA256
-
证书优化
-
证书传输:选择椭圆曲线(ECDSA)证书,在相同安全强度下, ECC 密钥长度比 RSA 短的多。
-
证书验证
-
CRL 称为证书吊销列表(Certificate Revocation List):
- CA 维护,客户端在更新 CRL 之前还是会信任这个证书,实时性较差;
- 随着吊销证书的增多,列表会越来越大,下载速度慢,验证延时很大
-
OCSP 在线证书状态协议(Online Certificate Status Protocol)
- 向 CA 发送查询请求,让 CA 返回证书的有效状态。如果网络状态不好,或者 CA 服务器繁忙,也会导致客户端在校验证书这一环节的延时变大。
-
OCSP Stapling
- 服务器向 CA 周期性地查询证书状态,获得一个带有时间戳和签名的响应结果并缓存它。
- 签名的存在,服务器无法篡改,客户端就能得知证书是否已被吊销了,不需要再去查询。
-
-
会话复用
首次 TLS 握手协商的对称加密密钥缓存起来,待下次需要建立 HTTPS 连接时,直接「复用」这个密钥
-
Session ID
-
客户端和服务器首次 TLS 握手连接后,双方会在内存缓存会话密钥,并用唯一的 Session ID 来标识
-
缺点:
- 随着客户端的增多,服务器的内存压力也会越大
- 多台服务器通过负载均衡提供服务,客户端再次连接不一定会命中,还要完整的 TLS 握手过程;
-
-
Session Ticket
- 服务器不再缓存每个客户端的会话密钥,而是把缓存的工作交给了客户端,类似于 HTTP 的 Cookie。
- 首次建立连接时,服务器会加密「会话密钥」作为 Ticket 发给客户端,交给客户端缓存该 Ticket。
- 对于集群服务器的话,确保每台服务器加密 「会话密钥」的密钥是一致的,这样客户端携带 Ticket 访问任意一台服务器时,都能恢复会话。
缺点
-
Session ID 和 Session Ticket 都不具备前向安全性
-
应对重放攻击也很困难
- 中间人截获了某个客户端的 Session ID 或 Session Ticket 以及 POST 报文,可以利用此截获的报文,不断向服务器发送该报文。
- 应该对会话密钥设定一个合理的过期时间
- Session ID 和 Session Ticket 方式都需要在 1 RTT 才能恢复会话。
-
Pre-shared Key
- 重连 TLS1.3 只需要 0 RTT,原理和 Ticket 类似,在重连时,客户端会把 Ticket 和 HTTP 请求一同发送给服务端。
- Pre-shared Key 也有重放攻击的危险