到目前为止,我们已经学习了HTTPS所有的必备知识,剩下的最后一个工作就是将前面所学全部串联起来,一旦串联成功,就是HTTPS的核心流程,某种意义上来说,HTTPS的核心流程和概念已经分散在前文中全部说完,本文仅是总结和抓包验证。
接下来让我们拿起抓包神器WireShark,来解剖HTTPS流程,并对前面所有知识进行验证和串联,这是一个不轻松的工作。
一、普通用户看到的HTTPS
在抓包前,我们来点铺垫。
为了让用户对HTTPS有直观的印象,浏览器开发商通过一种醒目的方式告诉用户其浏览的网站支持HTTPS,就是我们常见到的一把小锁图标。
这是我在谷歌浏览器访问截图模样,值得注意的是,小锁的定义没有统一的标准,不同的浏览器,甚至不同设备同一版本的浏览器,锁的表现形式也有一定的差别。
我在Edge上访问的模样是:
看到了小锁这个图标,则表示:
-
该页面使用的是HTTPS;
-
浏览器确认了服务器的合法身份;
打开开发者工具,选择【Security】选项,可以看到三部分信息:
-
HTTPS网站的证书信息;
-
协商出的密码套件、TLS协议版本等信息;
-
页面是否实施全站 HTTPS 策略;
好了,这个网站是真实的,用户可以放心使用。
二、TLS握手协议
TLS协议的交互流程在TLS官方文档中描述如下:
主要步骤是:
-
交换证书和密码学信息,进行服务器身份认证;
-
交换必要的密码学参数,客户端和服务器靠此能获取一致的预备主密钥;
-
通过预备主密钥和客户端/服务端交换的随机数生成主密钥;
-
客户端和服务端校验对方的Finished消息,避免握手协议消息被篡改;
针对以上TLS握手流程,我们稍加提前做下说明:
-
握手协议由很多子消息构成,对于完整握手来说,客户端和服务器端一般要经过两个来回才会完成握手。
-
星号标记表示对应的子消息是否发送取决于不同的密码套件, 比如 RSA 密码套件不会出现 ServerKey Exchange 子消息。
-
本流程不关注证书校验逻辑,之前已强调过PKI技术并不是TLS技术的一部分;
客户端和服务端必须按照顺序发送握手信息,否则会产生错误,下面结合抓包分析每一个流程。
三、HTTPS抓包准备
打开wireshark,选中当前使用的网卡,输入筛选条件:tls && ip.addr == 111.231.119.253
等待报文,随后我访问https://www.oursnail.cn/
,成功抓到了TLS握手报文,如下:
读者朋友们可以对任何使用了HTTPS的网站进行抓包分析,分析出来的流程都是一样的。
下面就进入枯燥的流程分析,咬咬牙硬着头皮干,也就两个来回,出发!
四、Client Hello
当客户端连接到服务器的时候,发送的第一条消息就是它:
-
(1)client_version :表示客户端支持的TLS协议版本,我们这里是TLS 1.2版本,表示兼容1.2及以下所有版本;
-
(2)random :客户端的随机数,该值非常有用,生成预备主密钥时会用到,使用PRF算法计算主密钥和密钥块会用到,校验完整的握手消息也会用到,总之每次连接都不能重复,我们称之为ClientHello.random;
-
(3)session_id :一个客户端和服务器完成一次握手,服务器会发送一个会话ID给客户端,下次连接的时候客户端会发送该会话ID给服务器,如果服务器端校验存在该会话ID就会恢复上次连接,从而减少握手过程,提升效率;而对于一次全新的连接来说, 客户端传递sessionid为空,启动完整握手过程;
-
(4)cipher_suites :客户端发送其支持的密码套件列表,可发送多个密码套件,排在第一个的优先;
-
(5)compression_methods :客户端支持的压缩方法,一般不启用;
-
(6)extensions :TLS协议支持扩展,以便将来在不用修改协议的基础上提供更多的可扩展;
本环节中最核心的两个信息,一个是客户端支持的密码套件,一个是客户端随机数。实际抓包中客户端发送了21个它支持的密码套件,相信读过上篇文章的读者朋友们可以大概理解其代表含义了。
值得注意的是,extensions中包含一个叫做 signature_algorithms ,该扩展包含客户端支持的所有数字签名算法,这与后续证书签名算法有关系,证书链中的证书签名算法需要客户端支持。
五、Server Hello
服务器端接收到客户端的 Client Hello 消息后,最重要的操作就是根据客户端传递过来的密码套件,结合服务器端配置的密码套件,选择一个双方都支持的密码套件,如果匹配错误,表示握手失败。
-
(1)server_version :服务器根据客户端传递的TLS协议版本号选择一个双方都支持的版本;
-
(2)random :和客户端一样,服务器端也会生成一个随机数,作用和客户端发送的随机数类似,我们称之为ServerHello.random;
-
(3)session_id :如果客户端传输的 session_id 不为空,则服务器会从缓存中寻找是否存在同样的session id,如果找到表示可以进行会话恢复,可以复用上一个连接。如果没有找到,则进行一个完整的握手过程,传递一个新的session_id。
-
(4)cipher_suites :服务器根据客户端传递的密码套件列表,选择一个双方都支持的密码套件并告知客户端;
-
(5)compression_methods :根据客户端传递的 compression_method ,决定使用的压缩算法,一般情况下不启用压缩算法;
-
(6)extensions :同Client Hello;
本环节结束后,双方协商出来一个可用的密码套件,可用从抓包里面看到协商出来的密码套件是TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,并且同样生成了一个服务端随机数。
结合上篇文章中对密码套件的解释,再次贴一下加强印象:
-
ECDHE:表示密钥协商算法采用ECDHE;
-
ECDSA:表示服务器公钥是ECDSA;
-
AES_256_GCM:AES是对称加密算法、加密模式是GCM、密钥长度是256比特;
-
PRF算法:TLS1.2版本使用的PRF算法加密基元默认是SHA256算法,这里采取了更加安全的SHA384算法;
六、Server Certificate
服务器发送 Server Hello 消息后,一般会立刻发送 Server Certificate 子消息。
此消息是服务器将其证书返回回来,该消息是可选的,在某些密码套件中不需要不发送该子消息的,不过会引起中间人攻击问题,正常情况下都是要返回的。
证书具体返回的是证书链,从抓包里面看包含了两张证书,分别是服务器实体证书和中间证书,服务器实体证书和中间证书都使用 ha256WithRSA 签名算法进行签名。
服务器公钥值可以在网页上对比是否正确:
总结下来,本次核心返回的是服务器证书,浏览器需要依靠此证书进行身份验证(证书链一级一级验签),核对服务器信息,确保拿到的服务器公钥是来自真实服务器的公钥。
七、Server Key Exchange和Server Hello Done
以上Server Hello协商出来的密码套件是TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,密钥协商算法采用ECDHE算法,服务器公钥是RSA的公钥。
既然属于DHE密钥协商算法,那么服务端自然需要返回动态的DH信息,包括DH参数和DH公钥,这些信息不在证书中,而是通过Server Key Exchange传递,此外,传递的DH信息需要使用服务器DH私钥进行签名,浏览器拿到DH参数后使用DH公钥验签确保信息的完整性,这一点已经在前文中说明DH密钥协商算法时多次强调过了。
关于椭圆曲线算法,每个人都可以自行指定椭圆曲线的公式、基点等参数,但TLS协议中一般使用已经命名好的命名曲线(named_curve),基点和参数已经固定,这里使用的ECC命名曲线是secp256r1,服务端只需要生成一个随机数(DH私钥),结合此类型椭圆曲线定义的参数和算法,即可计算出公钥,并将此公钥发送给客户端。
对应到抓包,DH服务端公钥就是抓包中的Pubkey:04c1e25c408a18f9d3ab269c2d7fdd1c5f45c9989f577a9a5fc94a052c3ee9df821170cf43dae9b2c61c268e231ed9f187960732eb8dd939a57c9efc8c4079462e,DH参数的签名值对应的是Signature,其值是:165e3c0fc0b6b1b…
Server Key Exchange是可选消息,只有使用到如下的密码套件时才会发送:
-
DHE DSS
-
DHE RSA
-
ECDHE ECDSA
-
ECDHE RSA
-
…
接下来看Server Hello Done:
服务器发送 Server Hello 等消息后会立刻发送该消息,表示服务端已经发送了足够的信息了,下面就是你客户端处理给我响应一些信息,我们一起协商出一个预备主密钥。
客户端收到该消息后,可以进行证书验证、协商密钥等步骤了。
八、Client Key Exchange
客户端收到服务端的Server Hello后,立刻发送此消息,该消息的主要目标是协商出预备主密钥。
-
如果密钥协商算法是RSA/ECDSA时,客户端通过服务端返回的 RSA/ECDSA 公钥加密预备主密钥,然后发送给服务器端,这里的预备主密钥就由客户端生成;
-
如果密钥协商算法是DH算法,通过服务器发送的 DH 参数计算出客户端的 DH 公钥,并传递给服务器,两者最终会计算出相同的预备主密钥;
-
如果密钥协商算法是ECDHE时,客户端需要根据服务器DH参数计算出客户端的ECDH公钥,并传递给服务器,两者最终会计算出相同的预备主密钥;
在使用DH或者ECDHE密钥协商算法时,客户端生成公钥的同时,还会生成私钥放在本地。
此时,通过密钥协商算法可以拿到安全的预备主密钥了,剩下的就是借助PRF算法计算出主密钥和各种算法需要的密钥块,这一点前文已经详细介绍过,这里就不再赘述了。
九、Change Cipher Spec
此时密钥已经协商完毕,客户端发送此消息,告知服务端已经计算出了主密钥和密钥块,因此这条消息并无实际数据,是一个事件通知。
这条消息一般由客户端先发送。对应的服务端也可以发送此消息通知给客户端。
十、Encrypted Handshake Message
理论上,密钥已经协商完毕,下面就是进行数据加密流程了,为什么还要发一条此消息呢?
还记得上篇文章中说的,当所有的握手消息都发送完毕后,需要对所有的握手消息进行完整性校验,我这里再贴一下加深印象:
-
客户端将发送和接收到的所有握手消息组合在一起,然后计算出摘要数据,握手层使用密钥块对摘要数据进行加密和完整性保护,然后发送给服务器(算总账能不能对的上)。
-
服务器接收到验证消息后,使用加密块解密出摘要数据。
-
紧接着服务器自行计算发送和接收的所有握手消息,再计算出消息的摘要数据,如果摘要数据和解密出的摘要数据相同,代表客户端发送的消息没有被篡改。(总账能对得上)
Finished 子消息有严格的顺序要求, 一定是在 ChangeCipherSpec 子消息之后发送 Finished 子消息,如果没有遵守该规定,会产生一个致命错误,一旦客户端和服务器端都校验了对方的 Finished 子消息,那么接下来就可以立刻加密保护应用层数据了。
简单来说,就是用新协商出来的密钥对所有的握手信息摘要数据进行加密发给服务端验证,一方面确保握手信息未被篡改,一方面还可以用来验证密钥正确性,一举两得。
反过来,服务端也需要发送此消息给客户端进行校验。
以上所有步骤结束,即可进行数据加密了,里面交互的数据都将被加密保护起来:
十一、补充说明
在做HTTPS流程总结之前,我想提一个问题:服务器公钥和证书签名算法关系是什么?
没有什么关系,服务器公钥会放在证书中,结合其他很多信息比如CA信息一起签名放在证书中。这里签名就涉及到证书签名算法,这个也是明文放在证书中的。
请务必区分证书签名的密钥对和服务器的密钥对。
还有一个问题:服务器公钥和密钥协商算法的关系是什么?
没有什么关系,我们以TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384密码套件为例,里面的RSA是服务器公钥是RSA算法生成的,而ECDHE是密钥协商算法。
虽然服务器公钥跟密钥协商算法没有啥关系,但是记住,服务器公钥是跟密码套件有关系。
密码套件中密钥协商算法不一样,其包含的服务器公钥作用也不一样,我们下面举例说明。
-
ECDHE_ECDSA
显然,ECDHE是密钥协商算法,ECDSA代表服务器证书公钥是ECDSA公钥。
客户端向服务器连接时,服务器需要传递动态的DH信息,如DH参数和服务端DH公钥,传递的DH信息为了防止篡改使用ECDSA私钥进行签名后发给客户端,客户端使用ECDSA公钥进行验签。
-
DH_RSA
DH是密钥协商算法,RSA代表服务器证书公钥是RSA公钥。
为了协商出预备主密钥,需要使用 DH 密码套件算法,由于是静态 DH 交换, DH 信息(DH参数和服务端DH公钥)是包含在证书中发送给客户端的。
在这种方式下,DH_RSA中的RSA公钥并没有发挥什么作用,不会用它进行加密或签名等操作。
可见,只有在动态DHE密钥协商算法中会发挥服务器公钥的作用,更直接点,是支持动态密钥的情况下,服务器公钥需要用来对传输的握手消息验签,当密钥是静态时,比如密钥协商算法是DH、RSA时,DH参数都是放在证书中传递给客户端的,此时不需要服务器公钥做加密或数字签名,因为证书本身就会做签名验证。
十二、总结
终于到了本文该结束的时候了,一开始就说过,HTTPS的核心流程和概念已经分散在前文中全部说完,本文仅是总结和抓包验证,如果读者朋友们完全看不懂,或者还云里雾里,还请多多研读前几篇文章,我相信前面铺垫的文章已经将本文所有的知识点都说明清楚了。
整体流程浓缩下来其实就如下几大步:
-
客户端发起请求,告知服务器自己支持的密码套件;
-
服务端选择一个双方都支持的密码套件,并返回证书发送给客户端;
-
客户端验证证书,确认服务器身份;
-
下面进行密钥协商,生成预备主密钥,继而生成主密钥和各种算法用到的密钥块;
-
最后进行握手消息的完整性校验,校验通过即可通过密钥进行加密数据和解密数据;
我画了一张大图:
前面这么多篇文章实际上都是围绕上面这几大步在说明,本文结合抓包将如上过程具象化,加深对HTTPS或者说对TLS1.2协议的理解。
最后提醒,本文主要基于ECDHE密钥协商算法来说明的,另外一种过时的RSA方案其实更加简单,由于本文已经很长,就不再赘述其流程了,本文完,下篇见。
原文始发于微信公众号(幕后哈土奇):七十三、进阶篇-HTTPS协议完整流程抓包和分析
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/113075.html