1. HTTPS协议原理分析1.1 需要解决的问题- 身份验证:确保通信双方身份的真实性。
- 通信加密:通信的机密性、完整性依赖于算法与密钥,通信双方是如何选择算法与密钥的。
1.2相关概念- 数字证书
- CA(certification authority):数字证书的签发机构。
- HTTPS协议、SSL协议、TLS协议、握手协议的关系
- HTTPS是Hypertext Transfer Protocol over Secure Socket Layer的缩写,即HTTP over SSL,可理解为基于SSL的HTTP协议。
- HTTPS协议安全是由SSL协议(目前常用的,本文基于TLS 1.2进行分析)实现的。
- SSL协议是一种记录协议,扩展性良好,可以很方便的添加子协议,而握手协议便是SSL协议的一个子协议。
- TLS协议是SSL协议的后续版本,本文中涉及的SSL协议默认是TLS协议1.2版本。
HTTPS协议的安全性由SSL协议实现,当前使用的TLS协议1.2版本包含了四个核心子协议:握手协议、密钥配置切换协议、应用数据协议及报警协议。
1.3 握手协议握手协议的作用便是通信双方进行身份确认、协商安全连接各参数(加密算法、密钥等),确保双方身份真实并且协商的算法与密钥能够保证通信安全。 协议交互图:
协议交互
- ClientHello消息的作用是,将客户端可用于建立加密通道的参数集合,一次性发送给服务端。
- ServerHello消息的作用是,在ClientHello参数集合中选择适合的参数,并将服务端用于建立加密通道的参数发送给客户端。
- Certificate消息的作用是,将服务端证书的详细信息发送给客户端,供客户端进行服务端身份校验。
- ServerKeyExchange消息的作用是,将需要服务端提供的密钥交换的额外参数,传给客户端。有的算法不需要额外参数,则ServerKeyExchange消息可不发送。
- ServerHelloDone消息的作用是,通知客户端ServerHello阶段的数据均已发送完毕,等待客户端下一步消息。
- ClientKeyExchange消息的作用是,将客户端需要为密钥交换提供的数据发送给服务端。
- ChangeCipherSpec消息的作用,便是声明后续消息均采用密钥加密。在此消息后,我们在WireShark上便看不到明文信息了。
- Finished消息的作用,是对握手阶段所有消息计算摘要,并发送给对方校验,避免通信过程中被中间人所篡改。
1.4 总结HTTPS如何保证通信安全,通过握手协议的介绍,我们已经有所了解。 但是,在全面使用HTTPS前,我们还需要考虑一个众所周知的问题——HTTPS性能。 相对HTTP协议来说,HTTPS协议建立数据通道的更加耗时,若直接部署到App中,势必降低数据传递的效率,间接影响用户体验。
2. HTTP 22.1 HTTP1.x协议随着互联网的快速发展,HTTP1.x协议得到了迅猛发展,但当App一个页面包含了数十个请求时,HTTP1.x协议的局限性便暴露了出来:
- 每个请求与响应需要单独建立链路进行请求(Connection字段能够解决部分问题),浪费资源。
- 每个请求与响应都需要添加完整的头信息,应用数据传输效率较低。
- 默认没有进行加密,数据在传输过程中容易被监听与篡改。
2.2 HTTP 2介绍HTTP2正是为了解决HTTP1.x暴露出来的问题而诞生的。
说到HTTP2不得不提spdy。 由于HTTP1.x暴露出来的问题,Google设计了全新的名为spdy的新协议。spdy在五层协议栈的TCP层与HTTP层引入了一个新的逻辑层以提高效率。spdy是一个中间层,对TCP层与HTTP层有很好的兼容,不需要修改HTTP层即可改善应用数据传输速度。 spdy通过多路复用技术,使客户端与服务器只需要保持一条链接即可并发多次数据交互,提高了通信效率。 而HTTP2便士基于spdy的思路开发的。 通过流与帧概念的引入,继承了spdy的多路复用,并增加了一些实用特性。
新特性:
- 多路复用
- 压缩头信息
- 对请求划分优先级
- 支持服务端Push消息到客户端
HTTP2目前在实际使用中,只用于HTTPS协议场景下,通过握手阶段ClientHello与ServerHello的extension字段协商而来,所以目前HTTP2的使用场景,都是默认安全加密的。
查看了wiki发现:
Netty and OkHttp are the only two implementations supported by Spring.
2.3 协议协商HTTP2协议的协商是在握手阶段进行的。
协商的方式是通过握手协议extension扩展字段进行扩展,新增Application Layer Protocol Negotiation字段进行协商。
在握手协议的ClientHello阶段,客户端将所支持的协议列表填入Application Layer Protocol Negotiation字段,供服务端进行挑选。
2.4 多路复用Multipexing在HTTP2中,同一域名下的请求,可通过同一条TCP链路进行传输,使多个请求不必单独建立链路,节省建立链路的开销。
为了达到这个目的,HTTP2提出了流与帧的概念,流代表请求与响应,而请求与响应具体的数据则包装为帧,对链路中传输的数据通过流ID与帧类型进行区分处理。下图是多路复用的抽象图,每个块代表一帧,而相同颜色的块则代表是同一个流。
http2 stream
归纳下okhttp的多路复用实现思路:
- 通过请求的Address与连接池中现有连接Address依次匹配,选出可用的Connection。
- 通过Http2xStream创建的FramedStream在发送了请求后,将FramedStream对象与StreamID的映射关系缓存到FramedConnection中。
- 收到消息后,FramedConnection解析帧信息,在Map中通过解析的StreamID选出缓存的FramedStream,并唤醒FramedStream进行Response的处理。
2.5 压缩头信息HTTP2为了解决HTTP1.x中头信息过大导致效率低下的问题,提出的解决方案便是压缩头部信息。具体的压缩方式,则引入了HPACK。
HPACK压缩算法是专门为HTTP2头部压缩服务的。为了达到压缩头部信息的目的,HPACK将头部字段缓存为索引,通过索引ID代表头部字段。客户端与服务端维护索引表,通信过程中尽可能采用索引进行通信,收到索引后查询索引表,才能解析出真正的头部信息。
HPACK索引表划分为动态索引表与静态索引表,动态索引表是HTTP2协议通信过程中两端动态维护的索引表,而静态索引表是硬编码进协议中的索引表。
作为分析HPACK压缩头信息的基础,需要先介绍HPACK对索引以及头部字符串的表示方式。
索引
索引以整型数字表示,由于HPACK需要考虑压缩与编解码问题,所以整型数字结构定义下图所示:
索引结构
- 类别标识:
通过类别标识进行HPACK类别分类,指导后续编解码操作,常见的有1,01,01000000等八个类别。 - 首字节低位整型:
首字节排除类别标识的剩余位,用于表示低位整型。若数值大于剩余位所能表示的容量,则需要后续字节表示高位整型。 - 结束标识:
表示此字节是否为整型解析终止字节。 - 高位整型:
字节余下7bit,用于填充整型高位。
|