HTTPS的详解
HTTP的缺陷
- HTTP采用的明文传输的方式,不安全,然后被窃听
- HTTP存在纂改的风险,比如植入广告等
- 冒充风险(中间人问题),比如冒充京东,返回错误的信息给用户
HTTPS解决HTTP存在的问题
- HTTPS在HTTP和TCP之间加了TSL/SSL解决了HTTP存在的问题
TLS是如何解决这些问题的?
- 信息加密:HTTP的信息是加密的,第三方是无法窃取的
- 检验机制:检验信息是否被第三方纂改过,如果纂改过会警告提示
- 身份证书:验证服务器是否是对应的服务器
由此可见,有了TLS/SSL(混合加密的方式)协议,能保证HTTP通信是安全的的了,在进行HTTP通信时,需要先进行TSL握手(在此之前要先进行TCP的三次握手)
不同的密钥交换算法
RSA算法交换
第一次TLS握手
- 客户端先发送一个【Client Hello】消息,消息里面包含了TLS的版本、支持的密码套件(通常是商量加密算法)以及随机生成的随机数1(使每一次HTTPS请求的密钥不唯一)
第二次TLS握手
- 当服务器收到客户端【Client Hello】的消息后,确认TLS的版本号,确认相对应的密码套件,以及生成随机数2
- 密码套件:密钥交换算法+签名算法+对称加密算法+摘要算法
- 然后服务器会向客户端发送CA证书
客户端验证证书
- 数字证书内容
- 公钥
- 持有者信息
- 证书的有效期
- CA对这份证书的签名及使用的算法
- 证书认证机构(CA)的信息
- 数字证书的作用:用来认证公钥持有者的身份,以防止被第三方冒充
- 数字证书的签发和验证流程
- 证书的验证:多级验证(客户端信任根证书依次类推检验相信中间证书,再检验相信对应的证书)
TLS的第三次握手
- 客户端验证完数字证书之后,认为可信便取出证书中的公钥,再生成一个随机数并通过对应的公钥进行加密,并将其发送给服务器
- 服务器接收之后,用私钥解密,这样客户端和服务器就同时拥有三个生成的随机数,再利用之前确定好的加密算法,客户端和服务器用三个随机数生成相对应的密钥(对称加密)
- 生成密钥之后,客户端向服务器发送【Change Cipher Spec】,告诉服务器开始用加密方式发送消息
- 接着客户端发送【Encrypted Handshake Message】消息做一个摘要,再用对称密钥加密一下,让服务器做个验证,验证本次生成的密钥是否正常使用
TLS的第四握手
- 最后,服务端也会有⼀个同样的操作,发「Change Cipher Spec」和「Encrypted Handshake Message」消息,如果双⽅都验证加密和解密没问题,那么握⼿正式完成。于是,就可以正常收发加密的 HTTP 请求和响应了
RSA的缺陷
- 无向前安全性:因为非对称加密时的私钥是固定不变,如果某一次请求中私钥被窃取了,会导致后面的请求都不安全
- 往返时间过长:TLS握手有四次也就是需要消耗两个RTT的时间,消耗的时间过长
ECDHE算法
交换密钥的过程
- 双方事先确定好相应的椭圆曲线,和曲线点G,这两个参数是公开的
- 双方各自随机生成一个随机数作为私钥d,并与基点G相乘得到公钥Q(Q=dG)
- 双方交换各自公钥,所以最终生成的生成的共享密钥是相同的(d1Q2=d1d2G=d2d1G=d2Q1)
TLS第一次握手
- 客户端⾸先会发⼀个「Client Hello」消息,消息⾥⾯有客户端使⽤的 TLS 版本号、⽀持的密码套件列表,以及⽣成的随机数
TLS第二次握手
- 服务端收到客户端的「打招呼」,同样也要回礼,会返回「Server Hello」消息,消息⾯有服务器确认的 TLS 版本号,也给出了⼀个随机数(Server Random),然后从客户端的密码套件列表选择了⼀个合适的密码套件
- 发送CA证书
- 选择了名为 named_curve 的椭圆曲线,选好了椭圆曲线相当于椭圆曲线基点 G 也定好了,这些都会公开给客户端
- ⽣成随机数作为服务端椭圆曲线的私钥,保留到本地;
- 根据基点 G 和私钥计算出服务端的椭圆曲线公钥,这个会公开给客户端
- 为了保证这个椭圆曲线的公钥不被第三⽅篡改,服务端会⽤ RSA 签名算法给服务端的椭圆曲线公钥做个签名。
TLS第三次握手
- 客户端会生成⼀个随机数作为客户端椭圆曲线的私钥,然后再根据服务端前⾯给的信息,生成客户端的椭圆曲线公钥,然后用「Client Key Exchange」消息发给服务端
- 最终的会话密钥,就是用[客户端随机数 + 服务端随机数 + x(ECDHE 算法算出的共享密钥) ]个材料生成的。
TLS第四次握手
- 最后,服务端也会有⼀个同样的操作,发「Change Cipher Spec」和「Encrypted Handshake Message」消息,如果双⽅都验证加密和解密没问题,那么握⼿正式完成。于是,就可以正常收发加密的 HTTP 请求和响应了