【CSDN有奖组稿】科技之路,共同进步,高品质移动发展,VR/AR/MR,物联网原创文章。请给mobilehub@csdn.net发一封电子邮件。
HTTPS协议原理分析 HTTPS协议需要解决的问题HTTPS作为一个安全协议而诞生,因此它必须面对以下两个主要的安全问题:
认证
保证双方身份的真实性。说白了,A想和B沟通,A如何确认B的身份不是C伪造的?
通信加密
通信的保密性和完整性取决于算法和密钥,以及双方如何选择算法和密钥。
如果能同时解决以上两个问题,就能保证真实有效的通信方采用有效的算法与密钥进行通信,进而完成协议安全的初衷。
在介绍HTTPS协议如何解决两个主要安全问题之前,我们首先了解几个概念。
数字证书
数字证书是在互联网通信中识别双方身份信息的数字文件,由认证机构颁发。
加利福尼亚
证书颁发机构是数字证书的颁发机构。作为权威机构,它在审查申请人的身份后签发数字证书,这样我们只需要验证数字证书就可以确定对方的真实身份。
HTTPS协议、SSL协议、TLS协议和握手协议的关系
HTTPS是安全套接层上超文本传输协议的简称,即SSL上的HTTP,可以理解为基于SSL的HTTP协议。HTTPS协议的安全性是通过SSL协议实现的(目前常用的,本文以TLS 1.2为基础进行分析)。
SSL协议是一种记录协议,具有良好的可扩展性,可以轻松添加子协议,握手协议是SSL协议的子协议。
TLS协议是SSL协议的后续版本,本文涉及的SSL协议默认为TLS协议1.2版。
HTTPS协议的安全性是通过SSL协议实现的,目前的TLS协议1.2版包含四个核心子协议:握手协议、密钥配置切换协议、应用数据协议和告警协议。
握手协议是认证和通信加密的核心。接下来,着重介绍握手协议。
信号交换协议
握手协议的作用是确认双方身份,协商安全连接的参数(加密算法、密钥等)。),从而保证双方的真实身份,协商的算法和密钥可以保证通信安全。
握手协议的引入仅限于客户端-服务器认证,单向认证也是互联网公司最常用的认证方式。
首先,让我们看看协议交互,如图1所示:
图1握手协议
接下来,以Wireshark抓取接口的握手协议流程为例,分析每个协议消息。
ClientHello消息
ClientHello消息的作用是一次性向服务器发送客户端可以用来建立加密通道的参数集。
消息内容包括预期的协议版本(TLS 1.2)、可用的密码套件、客户端随机数、扩展和其他信息,如图2所示。
图2客户端您好
服务器你好消息
服务器Hello消息的功能是从客户机Hello参数集中选择适当的参数,并将服务器用来建立加密通道的参数发送给客户机。
消息内容包括:采用的协议版本(TLS 1.2)、采用的密码套件、服务器随机数、会话标识(用于恢复会话的会话标识)、扩展字段,如图3所示。
从那时起,客户端和服务器之间的协议版本和密码套件就已经协商好了。
这里,服务器发出的会话ID可以用于后续的会话恢复。如果客户端在ClientHello中携带会话ID,并且服务器批准,则双方可以通过原主密钥直接生成新的一组密钥继续通信。将两次网络往返减少到一次网络往返,提高渠道建立效率。
图3服务器你好
证书消息
证书消息的目的是向客户端发送服务器证书的详细信息,以便客户端验证服务器身份。
消息内容:服务器颁发的证书链,如图4所示。
为了保证客户端能够正确识别出颁发的证书,服务器需要将颁发该证书的CA证书一起颁发,形成证书链,保证客户端能够根据证书链的信息在系统配置中找到根证书,并通过根证书的公钥逐层验证证书的有效性。
如图,58服务器颁发了两个证书:自己的证书和颁发CA的证书。通过颁发CA的证书信息,可以直接找到根证书。
图4证书
客户端在本地验证服务器证书。如果验证通过,客户端到服务器的身份验证就完成了。
证书解决了两端的认证问题。有了CA的权力,证书由CA颁发,认证交给CA。
只要是我们认可的CA,我们都认可证书持有人的身份。由于CA的介入,解决了中间人攻击的问题,因为中间人没有服务器的证书供客户端验证。
服务器密钥交换消息(可能无法发送)
服务器密钥交换消息的功能是将服务器提供的密钥交换的额外参数发送给客户端。有些算法不需要额外的参数,所以服务器密钥交换消息可能不会发送。
消息内容:密钥交换的附加参数,如图5所示。
图5服务器密钥交换
如图5所示,服务器发出“EC Diffile-Hellman”密钥交换算法所需的参数。
服务器错误消息
ServerHelloDone消息的目的是通知客户端服务器hello阶段的数据已经发送,等待客户端的下一条消息。
ClientKeyExchange消息
客户机密钥交换消息的目的是向服务器发送客户机提供密钥交换所需的数据。
当我们选择RSA密钥交换算法时,该消息的内容是由证书的公钥加密并用于生成主密钥的预主密钥。
如图6所示,因为选择的密钥交换算法是“EC Diffie-Hellman”,所以ClientKeyExchange消息发送“EC Diffie-Hellman”算法所需的客户端参数。
图6客户端密钥交换
客户端密钥交换发送时,两端都有完整的密钥数据和随机数生成主密钥,两端都可以根据选择的算法计算主密钥。
至此,ClientKeyExchange发送后,两端都可以生成主密钥,解决了密钥交换问题。
有些读者可能对随机数的使用有些怀疑。作者认为加入随机数是为了提高密钥的随机性。
因为客户端直接生成的密钥很可能不够随机,所以通过使用预主密钥加上两端提供的两个随机数作为种子,可以保证创建的主密钥更接近真实的随机密钥。
更改密码规格消息
经过以上六条消息,我们解决了身份认证、密码组选择和密钥交换等问题。双方还通过主密钥生成了六个实际使用的加密和解密密钥。
ChangeCipherSpec消息的功能是声明所有后续消息都是用密钥加密的。这条消息之后,我们就看不到WireShark上的明文信息了。
已完成的消息
Finished message的作用是计算握手阶段所有消息的汇总,并发送给对方验证,避免在通信过程中被中间人篡改。
HTTPS议定书概要
从那时起,我们就知道HTTPS如何通过引入握手协议来确保通信安全。
然而,在充分利用HTTPS之前,我们还需要考虑一个众所周知的问题——HTTPS的表现。
与HTTP协议相比,HTTPS协议建立数据通道更加耗时。如果直接部署在App中,必然会降低数据传输效率,间接影响用户体验。
接下来,我们介绍HTTPS性能拯救者——HTTP 2协议。
协议新宠HTTP 2协议介绍
随着互联网的飞速发展,HTTP1.x协议发展迅速,但是当一个App页面包含几十个请求时,HTTP1.x协议的局限性就暴露出来了:
每个请求和响应都需要建立一个单独的链接来发出请求(连接字段可以解决一些问题),这就浪费了资源。
每个请求和响应都需要添加完整的报头信息,应用数据传输效率低。
默认不加密,数据在传输过程中容易被监控和篡改。
HTTP2就是为了解决HTTP1.x暴露的问题而诞生的
说到HTTP2,不得不提spdy。
由于HTTP1.x暴露的问题,Google设计了一个新的协议,叫做spdy。Spdy在五层协议栈的TCP层和HTTP层引入了新的逻辑层,提高了效率。Spdy是中间层,兼容TCP层和HTTP层,在不修改HTTP层的情况下,可以提高应用数据传输速度。
通过复用技术,spdy使客户端和服务器能够多次交互,提高了通信效率。
而HTTP2是基于spdy开发的。
通过引入流和帧的概念,继承了spdy的复用性,并增加了一些实用特性。
HTTP2有什么特点?HTTP2的特性不仅解决了上述暴露的问题,还具有一些使HTTP协议更加有用的功能。
多路技术
压缩标题信息
优先处理请求
支持服务器向客户端推送消息
另外,目前HTTP2只在HTTPS协议场景中使用,在握手阶段通过ClientHello和ServerHello的扩展字段协商,所以目前HTTP2的使用场景默认都是安全加密的。
下面描述HTTP2协议协商的两个特点,复用和报头信息压缩。实现部分利用okhttp源代码(基于parent-3.4.2)进行分析介绍。
okhttp是目前使用最广泛的支持HTTP2的Android开源网络库。以okhttp为例介绍HTTP2特性,也可以方便读者提前了解okhttp,以后访问okhttp。
协议协商HTTP2协议的协商在握手阶段进行。
协商的方式是扩展握手协议扩展字段,增加一个应用层协议协商字段进行协商。
在握手协议的客户机Hello阶段,客户机在应用层协议协商字段中填写支持的协议列表,供服务器选择。如图7所示:
图7 ALPN1
收到ClientHello消息后,服务器从客户端支持的协议列表中选择适当的协议作为后续的应用层协议。如图8所示:
图8 ALPN2
这样,两端都完成了HTTP2协议的协商。
在没有HTTP2的情况下,spdy还通过扩展字段来扩展next_protocol_negotiation字段,并与NPN协议协商spdy。然而,由于NPN协商的复杂性,对https协议的入侵性很强,在ALPN协商协议出现后,逐渐被淘汰。因此,本文讨论了协议协商,并介绍了NPN协议的协商。
协议特性之多路复用为了优化http1.x对TCP性能的浪费,http2提出了复用的概念。
复用的意义
在HTTP2中,同一个域名下的请求可以通过同一个TCP链路传输,这样多个请求就不需要独立建立链路,节省了建立链路的开销。
为了达到这个目的,HTTP2提出了流和框架的概念。流表示请求和响应,而请求和响应的具体数据被打包成帧。链路中传输的数据根据流标识和帧类型进行不同的处理。图9是复用的抽象图,其中每个块代表一个帧,而相同颜色的块代表相同的流。
图9 http2_stream
那么HTTP2复用是如何实现的呢?
由于有许多网络请求的场景,我们选择其中一个路径来介绍:
已经在域名中的客户端和服务器之间建立了一个TCP通道
新创建的客户端请求通过连接的TCP通道发送和响应
多路复用实现
默认情况下,我们添加了各种参数来创建请求对象R,并通过请求对象创建了调用对象C。在独立线程中,调用c.execute()方法执行同步请求操作。
okhttp调用execute方法后,实际上是由一系列的拦截器执行的。
拦截器是按照添加的顺序执行的,其中我们关注的是RetryAndFollowUpInterceptor、ConnectInterceptor0和CallServerInterceptor。
1.在RetryAndFollowUpInterceptor中,okhttp为我们创建了一个StreamAllocation对象,其中包含一个基于url创建的Address对象。
地址类的url字段不同于请求类的URL字段。Address类的url字段不包含路径和查询字段,只包含方案和权限,这在Connection复用的平等操作中起着很大的作用。
2.在连接拦截器中,流分配对象的地址依次与连接池中每个连接对象的地址相匹配,匹配成功并满足某些条件的连接可以被重用。基于匹配的连接为后续的读写操作创建Http2xStream。
连接池中与Address的匹配主要是通过Address的url,url因为只包含方案和权限,所以可以用于域名匹配,这是基于域名级别的okhttp复用的基础。
其实真正的流读写操作是FramedConnection和FramedStream,Connection和Http2xStream是为了方便上层而从具体操作中抽象出来的类。
3.在CallServerInterceptor中,Http2xStream为请求发送创建一个FrameStream,用对应的StreamID缓存FrameStream绑定,这样在响应到来时,就可以根据StreamID索引来跟进操作。
在FramedStream发送请求后,执行readResponseHeaders方法时调用等待,当前线程被挂起。
当帧连接读取线程接收到流标识消息时,它会查询缓存中的帧流,并唤醒相应的线程进行响应解码。
总结okhttp的复用实现思路:
通过将请求的地址与连接池中现有的连接地址进行匹配,选择可用的连接。
由Http2xStream创建的FramedStream在发送请求后缓存FramedConnection中FramedStream对象和StreamID之间的映射关系。
收到消息后,帧连接解析帧信息,通过解析的流标识从映射中选择缓存的帧流,并唤醒帧流来处理响应。
在我看来,http2是一种与http协议格式兼容的自定义协议,通过Stream向请求分发数据,通过Frame对请求数据进行详细细分。
协议特性之压缩头信息为了解决HTTP1.x中报头信息过多导致效率低下的问题,HTTP2提出的解决方案是压缩报头信息。在具体的压缩模式中,引入了HPACK。
HPACK压缩算法专用于HTTP2报头压缩。为了压缩报头信息,HPACK缓存报头字段作为索引,索引ID代表报头字段。客户端和服务器端维护索引表,在通信过程中尽量使用索引进行通信,收到索引后查询索引表,从而分析出真实的表头信息。
HPACK索引表分为动态索引表和静态索引表。动态索引表是HTTP2协议通信时两端动态维护的索引表,静态索引表是硬编码到协议中的索引表。
作为分析H-pack压缩头信息的基础,有必要介绍H-pack如何表示索引和头字符串。
指数
索引用整数表示。由于HPACK需要考虑压缩、编码和解码,整数的结构定义如图10所示。
图10内部支柱
类别id
HPACK分类是通过类别识别来指导后续的编解码操作,共有1,010,100,000,000等八个常见类别。
第一个字节低整数
第一个字节不包括类别标识符的剩余位,后者用于指示较低的整数。如果该值大于剩余位表示的容量,则需要后续字节来表示高整数。
结束id
指示该字节是否为整数解析终止字节。
高整数
字节的剩余7位用于填充高整数位。
根据数据大小,可能有0个或更多“结束标识+高整数”字节。
例如,如果您想指示类为1,索引为2,可以使用10000010,并且不需要额外的字节来增加高整数。
标题字符串
头串的长度需要显式声明,所以数据的第一个字节由“类型标识符+数据长度”组成。如图11所示:
图11弦_支柱
类型id
是否选择霍夫曼编码,选择1,不选择0,okhttp默认不选择霍夫曼编码。
数据长度
标识数据长度,用上面提到的整数表示法表示。
数据内容
二进制数据。
解码示例
下面全面的okhttp源代码分析HPACK解码头字段的过程。
对编码感兴趣的读者可以参考RFC 7541或者直接分析OkHttp源代码。
当我们需要解码报头字段时,我们首先解析报头字段的第一个字节(HPACK报头字段的第一个字节分为8个类别,其中选择了3个类别描述),第一个字节用于指导当前报头字段的解析规则:
1xxxxxxx
类id为1,这意味着接收到一个以k和v为索引的头字段。
k,V值:通过解析HPACK整数得到KV对的索引值,根据索引值映射对应的头原字段,压缩效率最高。
01xxxxxx
类别ID为01,表示接收到以K为索引、V为原始字段的表头字段,需要添加到动态索引表中。
k值:k值的索引值是通过解析HPACK整数得到的,对应的头原字段由索引值映射。
v值:v值的原始字段是通过解析HPACK字符串得到的。
k和v的值需要插入到动态索引表中。
01000000
01000000表示k和v都是原始字段,需要添加到动态索引表的表头字段。
k和v值:k和v的原始字段通过解析HPACK字符串得到,并插入到动态索引表中。
有不添加动态索引表、调整索引表大小等类别,这里不展开。如果有兴趣,可以看看okhttp源代码的实现。
okhttp解析头信息的核心方法实现如下:
voidreadHeaders()引发IOException {
while(!source . excluded()){ int b = source . read byte()& amp;0xff
if(b = = 0x 80){//10000000//类别ID为1,但索引为0 0 throwenwioeexception(" index = = 0 ");} else if((b & amp;0x 80)= = 0x 80){//1 nnnnnn//类别为1,整数索引通过readIndexedHeader解析。int index = ReadNT(b,PREFX _ 7 _ BITS);
//通过index获取完整的表头字段readIndexedHeader(index-1);} else if(b = = 0x 40){//01000000//0100000表示KV为原字段。对字符串进行分析,依次得到k值和v值,插入到动态表read literatureheaderwith incrementalidenxignewname();} else if((b & amp;0x 40)= = 0x 40){//01 nnnnnn//01 xxxxx代表k值作为索引,v值作为原始字符串。依次解析整数索引和字符串,在动态表中插入int index = readint (b,prefix _ 6 _ bits);readliteralheaderwrithincrementalindexingindexed name(index-1);} else if((b & amp;0x 20)= = 0x 20){//001 nnnn//类别为001,表示更新动态列表容量maxdynamictablebytecount = readint(b,prefix _ 5 _ bits
if(MaxDynamiCTableByteCount & lt;0 | | MaxDynamiCTableByteCount & gt;headeratableizesetting){
thrownewIOException("无效动态表大小更新"+maxDynamicTableByteCount);} adjustDynamicTableByteCount();} elseif(b == 0x10|| b == 0) { // 000?0000-忽略从不索引位。//此类别表示KV为原始字符串,字符串依次解析,解析后的KV值不插入动态表。readLiteralHeaderWithoutIndexingNewName();} else{ // 000?NNNN-忽略从不索引位。//类似于前一类,但是k是索引,v是原字符串int index = readint (b,prefix _ 4 _ bits);readliteralheadrwithoutindexingindexed name(index-1);} }}
压缩效应
k值为“accept-encoding”v值为“g,deflate”的头字段,在HTTP2中可以用索引值15代替,从而达到头字段压缩的效果。
“accept-charset”报头字段用14表示报头k值,该值根据HPACK规则被编码并写入流中。
有了HPACK,一个报头字段变化少的App,会把每个报头字段压缩到4字节以下,压缩效果非常明显。
1.《clientkey HTTPS 与 HTTP2 协议分析》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。
2.《clientkey HTTPS 与 HTTP2 协议分析》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/fangchan/938305.html