1. 为什么需要HTTPS
我们都知道HTTP是明文传输的,在现实应用中暴露出了几个缺陷:
- 1. 隐私保护
HTTP是明文传输的,很容易被抓包,而这里边有可能包含我们登录银行的账号密码,危险性可想而知。
- 2. 完整性
同样是因为明文传输,整个传输链路里任意一个环节,都可以篡改/编辑传输内容,甚至劫持特定网站。
- 3. 身份认证
无法确定内容提供者身份,你收到的服务器响应可能是任意中间层生成(篡改)的,你甚至不知道请求有没有到源服务器
HTTPS就是为了解决上述问题而引入的。
2. HTTPS的定义
HTTP是超文本传输协议,工作中OSI七层模型里的应用层,HTTPS是在HTTP协议下加了一个SSL/TLS层,用于加密数据传输。 SSL/TLS也被划分到应用层,锁HTTPS的子协议。
SSL全名Secure Socket Layer,是Netscape提出的,随着Netscape公司的没落,SSL被转交给了IETF(Internet Engineering Task Force),IETF对SSL标准化后重命名为TLS(Transport Layer Security),所以一般我们把两个名字放一起,称为SSL/TLS协议簇。
HTTPS中的S
是Security
的意思,可以认为HTTPS = HTTP + SSL/TLS
。
2.1 SSL/TLS发展史
- SSL最先有Netscape提出,SSL 1.0没有对外公布
- 1995年,Netscape发布了SSL 2.0,因为存在严重的安全漏洞,同年发布了SSL 3.0
- Netscape没落后,SSL交由IETF管理维护,IETF将SSL重新命名为TLS
- 1999年,IETF发布了TLS 1.0,大部分功能继承自SSL 3.0,相当于是SSL 3.1版本
- 2006年,IETF发布了TLS 1.1
- 2008年,IEFT发布了TLS 1.2
- 2013年,主流浏览器开始使用TLS 1.2,离发布日期整整差了5年
- 2015年,主流浏览器开始放弃支持SSL 3.0
- 2018年,IETF发布了TLS 1.3,进一步改进安全性
- 2020年,大部分浏览器(>99.5%)使用TLS 1.2或1.3,主流是TLS 1.2,1.3还在路上;
- 现状,Chrome 72开始不推荐使用TLS 1.0和1.1,Chrome 81之后完全不支持;
Firefox、Edge、Safari在2020年后会移除TLS 1.0和1.1的支持
2.2 HTTPS证书
通过浏览器的左上角这边小锁,能过查看证书详情:
证书里包含的信息有:
- 颁布给谁,域名
- 有效期
- 颁发者,具体的证书服务商
- 服务端公钥
- 指纹,证书的明文数据摘要,然后用证书服务商私钥加密后的数据
2.3 HTTPS证书颁发/验证流程
图的左侧是证书的生成流程:
- 我们提供自己的信息(域名、公钥、有效期等等),向证书服务商提出申请
- 证书服务商根据我们的信息生成摘要
- 证书服务商对摘要使用私钥加密(非对称加密)
- 我们的公开信息 + 加密后的摘要,组成一个完整的证书
图的右侧是证书的验证流程:
- 证书里包含两部分数据,公开信息 + 加密后摘要
- 客户端对证书的公开信息重新计算摘要
- 客户端用证书的颁发者的公钥对证书内
加密后摘要
解密 - 如果自己计算的摘要和解密后的摘要一致,证书验证通过
2.4 HTTP工作流程
- TCP连接建立后,现有客户端发送
Client Hello
,发送的信息包括:- 客户端支持的SSL/TLS版本
- 客户端支持的加密套件(加密算法)
- 客户端生成随机数client_random
- 会话ID(sessionId),为避免短时间内重复握手
- 少数情况下客户发也需要发送证书,如银行给客户提供的U盾
- 服务器收到客户端的
Client Hello
后,根据客户端支持的版本/加密套件,选择后返回:- 选择的SSL/TLS版本
- 选择的加密套件
- 服务端生成的随机数server_random
- 会话ID(sessionId)
- 服务器证书,为了让客户端验证身份
- 客户端校验服务器返回的证书,我们来看一下验证过程:
- 证书校验
- 客户端有一批预设的证书服务商的根证书,受信的证书颁布的证书也会被认为是可信任的
- 常见证书服务商: GlobalSign、GeoTruest、Verisign,国内云厂商也提供证书服务
- 服务端要支持HTTPS,需先从证书服务商申请HTTPS证书
- 服务端网关配置HTTPS,提供HTTPS证书
- 客户端从服务端下载HTTPS证书,校验证书有效性以确定服务端身份
- 产生随机数pre-master
- 证书校验
- 交换pre_master
- 因为第1、2步是明文传输,直接用这2步生成对称加密密钥的话,中间层仍然可以截获、伪造
- pre-master通过公钥加密,即使截获也无法解密,这样确保中间层拿不到加密密钥
- 生成客户端密钥,计算方式:
- 密钥=摘要算法(client_random, server_random, pre-master)
- 生成服务端密钥,计算方式:
- 密钥=摘要算法(client_random, server_random, pre-master)
- 客户端/服务器这三个值都是一致的,所以最后使用的密钥是一致的
- Client finished
- 不确定实际作用,猜测是发测试数据,确保客户端-服务端链路通畅,能正常解密
- Server finished
- 不确定实际作用,猜测是发测试数据,确保服务端-客户端链路通畅,能正常解密
- HTTP协议
- 正常发送HTTP协议的内容通信,唯一的不同的使用了对称加密
- 会话产生是因为服务端并发处理多个客户端请求,需要知道哪个请求用哪个密钥
- 从安全性、服务器内存来看,密钥不可能是永远有效,需要一个机制有序退出
3. 参考资料
- https://stephanietang.github.io/2020/04/19/how-https-works/