# HTTPS

我们使用 HTTP 传输的内容很容易被中间人窃取、伪造和繁改,通常我们把这种攻击方式称为中间人攻击

# 什么是 HTTPS

“明文”和“不安全”仅凭 HTTP 自身是无力解决的,需要引入新的 HTTPS 协议,从“HTTP over HTTP ”变成了“ HTTP over SSL/TLS”,让 HTTP 运行在了安全的 SSL/TLS 协议上, 收发报文不再使用 Socket API,而是调用专门的安全接口。

通常我们认为,如果通信过程具备了四个特性,就可以认为是“安全”的,这四个特性是:机密性完整性身份认证不可否认

# HTTPS 和 HTTP 有什么区别

  1. HTTPSTCP/IP 的基础上,增加了一层 SLL/TCL 进行安全验证,使报文能够加密传输
  2. HTTP 建立简单,只需要经过三次握手即可进行报文传输,HTTPS 在之后还需要进行 SSL/TLS 握手
  3. HTTP 的端口号是 80HTTPS 则是443
  4. HTTPS 需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的。

# SLL/TLS 又是如何进行加密的呢

加密是针对安全的 4 个特性进行的逐层加密。

# 机密性

实现机密性最常用的手段就是加密,就是把消息用某种方式转化成乱码。 明文 通过 加密算法 ==> 密文
使用 秘钥 还原 明文 的过程叫 解密

按照秘钥的使用方式,可以分成两大类:对称加密和非对称机密;

# 对称加密

加密和解密使用的都是同一个秘钥。只要保证了秘钥的安全,整个通信过程就可以说具有机密性了

目前常用的对称加密算法只有 AESChaCha20

# 加密分组模式

对称算法还有一个“分组模式”的概念,它可以让算法用固定长度的密钥加密任意长度的明文,把小秘密 (即密钥)转化为大秘密(即密文)。

最新的分组模式被称为 AEAD,在加密的同时增加了认证的功能,常用的是GCMCCMPoly1305。 把上面这些组合起来,就可以得到 TLS 密码套件中定义的对称加密算法。 举个栗子,AES128-GCM,意思是密钥长度为 128 位的 AES 算法,使用的分组模式是 GCM;ChaCha20-Poly1305 的意思是 ChaCha20 算法,使用的分组模式是 Poly1305。

# 非对称加密

在讲对称加密的时候也提到了,需要保证秘钥的安全。那么我们应该如何交换这个秘钥?

非对称加密,它有两个秘钥,公钥私钥 ,公钥可以公开给任何人使用,而私钥必须严格保密。 非对称加密可以解决“密钥交换”的问题。网站秘密保管私钥,在网上任意分发公钥,你想要登录网站只要用公钥加密就行了,密文只能由私钥持有者才能解密。而黑客因为没有私钥,所以就无法破解密文.

非对称加密算法的设计要比对称算法难得多,在 TLS 里只有很少的几种,比如 DHDSARSAECC 等。

  • RSA:它的安全性基于“ 整数分解 ”的数学难题,使用两个超大素数的乘积作为生成密钥的材料,
  • ECC:基于“ 椭圆曲线离散对数 ”的数学难题,使用特定的曲线方程和基点生成公钥和私钥,子算法 ECDHE 用于密钥交换,ECDSA 用于数字签名

比起 RSA,ECC 在安全强度和性能上都有明显的优势

# 混合加密

非对称加密虽然实现了机密性,但因为基于数学难题,运算速度很慢,抛弃了速度,所以在 TLS 中采用了混合加密的方式。

混合加密方式:用随机数产生对称算法使用的“会话密钥 ”(session key),再用公钥加密。因为会话密钥很短,通常只有 16 字节或 32 字节,所以慢一点也无所谓。然后对方拿到 “会话密钥 ” 再用私钥解密,这就完成了对称秘钥交换。

# 完整性

# 摘要算法

摘要算法近似地理解成一种特殊的压缩算法,它能够把任意长度的数据“压缩”成固定长度、而且 独一无二的“摘要”字符串,就好像是给这段数据生成了一个数字“指纹”,是一种单向的加密算法。

我们日常工作常用的MD5SHA-1就是摘要算法

目前 TLS 推荐使用的是 SHA-1 的后继者:SHA-2。

# 完整性 1

摘要算法保证数字摘要原文是完全等价的。所以,我们只要在原文后附上它的摘要,就能够保证数据的完整性。 如果黑客在中间哪怕改动了一个标点符号,摘要也会完全不同,网站计算比对就会发现消息被窜改,是不可信的。

但是,真正的完整性必须要建立在机密性之上,在混合加密系统里用会话密钥加密消息摘要

# 数字签名

数字签名是为了解决通信两端的信任问题。 它通过将非对称加密里的“私钥 ”,使用私钥再加上摘要算法,就能够实现“数字签名”,同时实现“身份认证”和“不可否认”。

签名和公钥一样完全公开,任何人都可以获取。但这个签名只有用私钥对应的公钥才能解开,拿到摘要后, 再比对原文验证完整性,就可以像签署文件一样证明消息确实是你发的。

# 数字证书和 CA

CA (Certificate Authority,证书认证机构),具有极高的可信度,由它来给各个公钥签名,用自身的信誉来保证公钥无法伪造, 是可信的。

CA 对公钥的签名认证也是有格式的,不是简单地把公钥绑定在持有者身份上就完事了,还要包含序列号用途颁发者有效时间等等,把这些打成一个包再签名,完整地证明公钥关联的各种信息,形成“数字证书”(Certificate)。

CA

小一点的 CA 可以让大 CA 签名认证,但链条的最后,也就是 Root CA ,就只能自己证明 自己了,这个就叫“自签名证书 ”(Self-Signed Certificate)或者“根证书 ”(Root Certificate)。你必须相信,否则整个证书信任链就走不下去了。

总结为以下三点:

  1. 申请数字证书是不需要提供私钥的,要确保私钥永远只能由服务器掌握;

  2. 数字证书最核心的是 CA 使用它的私钥生成的数字签名;

  3. 内置 CA 对应的证书称为根证书,根证书是最权威的机构,它们自己为自己签名,我们把这称为自签名证书。

# 证书体系的弱点

如果 CA 失误或者被欺骗,签发了错误的证书,虽然证书是真的,可它代表的网站却是假的。 还有一种更危险的情况,CA 被黑客攻陷,或者 CA 有恶意,因为它(即根证书)是信任的源头,整个信任链里的所有证书也就都不可信了。

# 密码套件

TLS 的密码套件命名非常规范,格式很固定。基本的形式是“密钥交换算法+签名算法+对称加密算法+分组模式 +摘要算法

举个栗子:server suite : ECDHE-RSA-AES256-GCM-SHA384 server suite 意思是:“握手时使用 ECDHE 算法进行密钥交换,用 RSA 签名和身份认证,握手后的通信使用 AES 对称算法,密钥长度 256 位,分组模式是 GCM,摘要算法 SHA384 用于消息认证和产生随机数。

# 连接过程解析

image-20200918173057621

# TSL1.2

  1. TCP3 次握手
  2. Client Hello" 里面有:客户端的 版本号支持的密码套件随机数(Client Random)
  3. "Server Hello" ,对版本号,选择一个密码套件,返回一个 随机数(Server Random)
  4. "Server Certificate" 把证书也发给了客户端。
  5. "Server Key Exchange" ,发送 公钥(Server Params)私钥签名认证
  6. "Server Hello Done " 服务器表示信息发完了

这样第一个消息往返就结束了(两个 TCP 包),结果是客户端和服务器通过明文共享了三个信息:Client RandomServer RandomServer Params

  1. "Client Key Exchange" 发送 公钥(Client Params)
  • Change Cipher Spec

客户端和服务器将 公钥(Server Params)公钥(Client Params)使用 ECDHE 算法一阵算,算出一个新的随机数 “Pre-Master

再使用Client RandomServer RandomPre-Master生成用于加密会话的主密钥“Master Secret

  1. Client “Change Cipher Spec”,计算出主秘钥
  2. Client “**Finished **” 把之前所有发送的数据做个摘要,再加密一下,等待服务器验证
  3. Server “Change Cipher Spec”,计算出主秘钥
  4. Server “**Finished **” 双方都验证加密解密 OK,握手正式结束

# TSL1.3

因为密码套件大幅度简化,也就没有必要再像以前那样走复杂的协商流程了。TLS1.3 压缩了以前 的“Hello”协商过程,删除了“Key Exchange”消息,把握手时间减少到了“1-RTT”,效率提高了一倍。

  • 首先浏览器向服务端发送 Client -random可使用的对称密码套件和非对称加密套件
  • 服务器端保存 Client-random,并返回 server-random选择的密码套件公钥(这里加上 CA 发送的是数字证书)、密钥交换算法的公钥(Server Params)
  • 浏览器拿到数据后,也生成一个Client Param ,对 Client -randomserver-random ,Server Params,Client Params使用 ECDHE 算法 生成 Pre-master,并使用公钥加密发送给服务器

pre-master 是经过公钥加密之后传输的,所以黑客无法获取到 pre-master,这样黑客就无法生成密钥,也就保证了黑客无法破解传输过程中的数据了

  • 服务器收到后,使用私钥解密并验证合法性,至此,两边就都可以通过 cilent-randomserver-randomPre-master 三个共同随机数生成对称秘钥(Master Secret)进行加密传输了
master_secret = PRF(
  pre_master_secret,
  "master	secret",
  ClientHello.random + ServerHello.random
);

这里的“PRF”就是伪随机数函数,它基于密码套件里的最后一个参数,

# 双向认证

上面说的是“单向认证 单向认证”握手过程,只认证了服务器的身份,而没有认证客户端的身份。这是因为通常 单向认证通过后已经建立了安全通信,用账号、密码等简单的手段就能够确认用户的真实身份。

但为了防止账号、密码被盗,有的时候(比如网上银行)还会使用 U 盾给用户颁发客户端证书,实现“ 双向认证”,这样会更加安全。 双向认证的流程也没有太多变化,只是在“Server Hello Done ”之后,“Client Key Exchange Client”之前,客户端要发送“ Client Certificate”消息,服务器收到后也把证书链走一遍,验证客户端的身份。

# 常见问题

# 客户端如何验证证书的合法性

操作系统和浏览器等在安装时候就预装了 CA(证书机构)列表,服务商在使用 https 前,会向 CA 请求颁发签名,在建立 https 连接的时候,浏览器会查看证书签名颁发机构是否在 CA 列表,如果是表示可以信任。

具体是,服务端生成密钥对(k1,k2), 将实体信息以及 k1 发送给 CA,获取证书,CA 对签名内容 hash 生成消息摘要,CA 用自己私钥 k2-CA 对消息摘要加密,生成签名,浏览器在校验时,获取到相应 CA 的公钥(预装),对签名解密,获取消息摘要,同时通过相同的 hash 函数对证书消息 hash 生成摘要,两者对比,如果相同则信任

# 为什么要证书

客户端和服务端会使用双方的公钥生成一个随机数Pre-Master,然后再使用三个随机数生成传输使用的主密钥,如果中间人冒充,对两边的公钥进行伪造,则后面的加密都将无效,而 CA 就用于保证,你获得的公钥确实是你要访问的可靠网站的公钥,而不是别人冒充的。

# HTTP 传输消息都是明文的,黑客完全可以作为中间人劫持消息,再利用 ECDHE 算法,这样不就能破解密钥了吗?

ECDHE 算法利用了椭圆曲线和离散对数等思想,按照当下的计算机算力,很难在短时间进行破解。且每次握手时生成的都是一对临时的公钥和私钥,这样就保证每次的密钥对也不同。

即使大费力气破解了一次的密钥,之前的历史消息也不会受到影响,保证了前向安全。

# 为什么要是三个随机数

TLS 的设计者不信任客户端或服务器伪随机数的可靠性,为了保证真正 的“完全随机”“不可预测”,把三个不可靠的随机数混合起来,那么“随机”的程度就非常高了,足够让 黑客难以猜测。


《透视 HTTP 协议》 (opens new window)

《feiker 的 https 笔记》 (opens new window)

《硬核!30 张图解 HTTP 常见的面试题》 (opens new window)

《深入揭秘 HTTPS》 (opens new window)

《完全图解 HTTPS》 (opens new window)

Last Updated: 12/22/2022, 9:53:26 AM