TLS握手协议分析与理解——某HTTPS请求流量包分析

https://xz.aliyun.com/t/1039html

 

HTTPS简介

  • HTTPS,是一种网络安全传输协议,在HTTP的基础上利用SSL/TLS来对数据包进行加密,以提供对网络服务器的身份认证,保护交换数据的隐私与完整性。
    • TLS(Transport Layer Security)1.0是SSL(Secure Sockets Layer)3.0的升级版,安全套接字层协议,承担的角色都是同样的,是HTTPS方式握手以及传输数据的一个协议。只是改了名字,其中的八卦,感兴趣的朋友能够本身去搜索。
  • HTTP(S)协议是在TCP/IP协议基础上建造的。
  • TCP/IP协议的分层管理,按层次分为:应用层、传输层、网络层、数据链路层。(咱们常说的四层协议、四层模型就是指的这个啦)
  • 没有通过加密层时,数据传输的路径是:应用层->传输层->网络层->数据链路层
  • 通过加密层以后,数据传输的路径是:应用层->SSL/TLS层->传输层->网络层->数据链路层
  • 每层常见的协议:
    • 应用层协议有:FTP、Telnet、SMTP、HTTP、RIP、NFS、DNS。
    • 传输层协议有:TCP协议、UDP协议。
    • 网络层协议有:IP协议、ICMP协议、ARP协议、RARP协议。

HTTPS用途

  • 防窃听:HTTPS协议对传输数据的内容加密,保障数据在传输过程的安全(加密传播)
  • 防冒充:确认网站的真实性(身份证书)
  • 防篡改:防止内容被第三方篡改(校验机制)

HTTPS协议安全性

  • HTTPS协议自己是安全的,而且可以保障数据传输安全、两端身份真实、以及检查数据是否被篡改。
  • 但近几年有https相关的漏洞频发,如心血漏洞、中间人攻击、DROWN溺水攻击、FREAK漏洞、降维攻击、POODLE等(近期会将每一个漏洞原理进行分析)。不禁让人为https的安全性担心,其实这个协议的逻辑通常是设计的很是安全了,即便出现问题,也会有大版本的升级(如TLS 1.0升级为TLS 1.1)。并且频发漏洞的并非https协议自己,而是各个开源或商业服务在具体实现https时,出现了安全问题。

https如何进行数据传输的?

  • 大体流程是:进行握手流程创建https链接(此时是明文传输),而后再进行真正的数据传输(此时使用对称加密进行密文传输)
  • 首先须要了解TLS/SSL协议握手的过程

握手过程

  • 整个过程,如访问www.baidu.com
    • 先进行DNS解析,再创建TCP链接,而后进行https握手,最后传输加密数据。

握手消息 动做描述 消息内容
1. Client —> ClientHello —> Server 客户端(浏览器)发送一个hello消息给服务端,发起创建SSL会话的请求。并告诉服务端,本身支持哪些加密算法(Cipher Suite List)。除此以外,还须要产生一个随机数(第一个随机数,用于之后生成对称密钥),发送给服务端。 1)支持的协议版本,如TLS 1.0版<br/>2)由客户端生成的随机数,用于生成后面的“对称密钥”<br/>3)支持的加密方法,好比RSA公钥加密<br/>4)支持的压缩方法<br/>5)请求的域名<br/>
2. Server —> ServerHello —> Client 服务端的首次响应,会肯定加密协议版本,以及加密的算法,也会生成一个随机数(第二个随机数)给客户端。 1)协议的版本<br/>2)加密的算法<br/>3)服务端生成的随机数<br/>
3. Server —> Certificate —> Client 还会把本身的证书发送给客户端,让客户端进行校验。服务端证书中的公钥也可被用于加密后面握手过程当中生成的对称密钥。 1)服务端证书<br/>证书颁发机构的名称<br/>证书自己的数字签名<br/>证书持有者公钥<br/>证书签名用到的Hash算法<br/>
4. Server --> ServerKeyExchange —> Client 指定使用哪一种密钥协商协议。服务端能够在ServerKeyExchange以后当即发送CertificateRequest消息,要求校验客户端的证书。 1)使用哪一种密钥协商方式<br/>2)密钥协商时客户端须要的信息
5. Server —> ServerHelloDone —> Client 服务器发送ServerHelloDone消息,告知客户端服务器这边握手相关的消息发送完毕。  
6. Client —> ClientKeyExchange —> Server 消息中包含客户端这边的EC Diffie-Hellman算法相关参数,而后服务器和客户端均可根据接收到的对方参数和自身参数运算出对称密钥。 1)密钥协商时服务端须要的信息
7. Client —> ChangeCipherSpec —> Server ChangeCipherSpec消息,通知服务器此消息之后客户端会以加密方式发送数据。 准备好了作加密传输的通知
8. Client —> Finished —> Server 客户端计算生成对称密钥,而后使用该对称密钥加密以前全部收发握手消息的Hash值,发送给服务器,服务器将相同的会话密钥(使用相同方法生成)解密此消息,校验其中的Hash值。  
9. Server —> ChangeCipherSpec —> Client ChangeCipherSpec消息,通知客户端此消息之后服务器会以加密方式发送数据。 准备好了作加密传输的通知
10. Server — > Finished —> Client 服务器使用对称密钥加密(生成方式与客户端相同)以前所发送的全部握手消息的hash值,发送给客户端去校验。  
11. Application Data 真正的数据传输(使用对称加密)

1. Client Hello

  • 客户端发起TLS握手请求
    struct { ProtocolVersion client_version; Random random; SessionID session_id; CipherSuite cipher_suites<2..2^16-2>; CompressionMethod compression_methods<1..2^8-1>; select (extensions_present) { case false: struct {}; case true: Extension extensions<0..2^16-1>; }; } ClientHello; 
  • 数据包括内容:
    • ProtocolVersion/协议版本(客户端指望支持的握手协议版本
    • Random/安全随机数(MasterSecret生成用到,协议文档里面说是28个字节,可是实际抓包看到是32个字节,这里怀疑是各个协议文档版本不一样,还有使用加密套件的不一样,致使的差别,具体博主就没有在继续深究了,若是有朋友知道能够留言给我)
    • SessionID/会话ID
      • 这个值是被服务端设置的,若是这个值为空,表示客户端与服务端没有存活的https会话,须要与服务端进行完整的握手。
      • 若是这个值存在,则代表客户端指望恢复上一次的https会话,这时候客户端与服务端只须要进行快速的握手过程。(这里咱们只会分析完整的握手过程进行学习)
    • CipherSuite/加密套件(客户端支持的加密套件列表)
      • 若是sessionid不为空,能够不传这个值,服务端能够从上一次会话中恢复这个值。
      • 每一个加密组件(Cipher Suite)都包括了下面5类算法 TLS Cipher Suite Registry,图中百度使用的是就是 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 这个加密套件:
        • 一、authentication (认证算法):RSA
        • 二、encryption (加密算法 ):AEAD_AES_128_GCM
        • 三、message authentication code (消息认证码算法 简称MAC):SHA256
        • 四、key exchange (密钥交换算法):ECDHE
        • 五、key derivation function (密钥衍生算法)
    • CompressionMethod/压缩方法
      • 加密前进行数据压缩
      • 由于压缩方法被攻击,在TLS1.3协议版本上已经完全禁止压缩了。(这里有两种攻击方式BREACH、CRIME,有时间博主会来研究)
    • Extension/扩展数据(session ticket在扩展里面,可见下图)
  • 消息内容以下图:

2. Server Hello

  • 服务端回应Client Hello请求
    struct { ProtocolVersion server_version; Random random; SessionID session_id; CipherSuite cipher_suite; CompressionMethod compression_method; select (extensions_present) { case false: struct {}; case true: Extension extensions<0..2^16-1>; }; } ServerHello; 
  • 主要发送数据内容:
    • ProtocolVersion/握手协议版本
      • 服务端最高支持的握手协议版本,TLS/SSL协议都是向下兼容的。
    • Random/随机数
      • 服务端生成32字节安全随机数(MasterSecret生成会用到)
    • SessionID/会话ID
      • 若是客户端hello有发送session id,服务端从内存中查找,并尝试恢复以前的会话状态。
        • 恢复成功,服务端返回一样的session id。
        • 恢复不成功,服务端此字段返回空。
    • CipherSuite/加密组件
      • 服务端从客户端hello的cipher suite列表中选择一个加密套件,若是是恢复上一次的会话,则从会话状态中恢复上一次相同的加密套件。
    • CompressionMethod/压缩方法
      • 服务端从客户端hello的compression_methods列表中选择一个压缩方法,若是是恢复上一次的会话,则从会话状态中恢复上一次相同的压缩方法。
    • Extension/扩展(以下图)
  • 消息以下面所示:

3. Server Certificate

  • 服务端发送的是一个证书链,可能包含多个证书
    • 第一个证书为网站的证书。
    • 第二个证书为颁发证书给网站的机构的证书。
    • 在这个例子中第三个证书是CA机构的根证书,能够忽略不用发送,由于这个CA的根证书是CA本身给本身颁发的。
      这里构成了一个证书信任链,也就是 GlobalSign Root CA信任GlobalSign Organization Validation CA,而他又信任baidu.com的证书。
      以下图所示:

  • CA证书的类型有3类:DV ( domain validation),OV ( organization validation),EV ( extended validation),证书申请难度从前日后递增。
  • 证书中都包含了哪些信息?
    ```html
  • 证书版本号(Version)
  • 证书序列号(Serial Number)
  • 签名算法标识符(Signature Algorithm)
    签名算法标识用来指定由CA签发证书时所使用的"签名算法"。算法标识符用来指定CA签发证书时所使用的:
    1) 公开密钥算法
    2) hash算法
    example: sha256WithRSAEncryption
    须向国际知名标准组织(如ISO)注册
  • 签发机构名(Issuer)
  • 有效期(Validity):指定证书的有效期
  • 证书用户名(Subject)
  • 证书持有者公开密钥信息(Subject Public Key Info)
    证书持有者公开密钥信息域包含两个重要信息:
    1) 证书持有者的公开密钥的值
    2) 公开密钥使用的算法标识符。此标识符包含公开密钥算法和hash算法。
  • 扩展项(extension)
  • 签发者惟一标识符(Issuer Unique Identifier)
  • 证书持有者惟一标识符(Subject Unique Identifier)
  • 签名算法(Signature Algorithm)
  • 签名值(Issuer's Signature)
    ```
  • 以下图所示

如何校验服务端证书呢?

  • 签名的生成:CA先将证书信息生成hash摘要,而后再用CA机构的私钥进行加密。
  • 签名的校验:使用CA机构的公钥进行解密签名,获得hash摘要A,再计算证书信息的hash摘要B。比对是否一致。
    #### 详细解释服务端的证书是怎么生成的?
  • 服务端的证书是由CA (Certificate Authority,证书认证中心)颁发的。他是一个负责发放和管理数字证书的第三方权威机构,它负责管理PKI(Public Key Infrastructure,公开密钥基础设施)结构下的全部用户(包括各类应用程序)的证书,把用户的公钥和用户的其余信息捆绑在一块儿,在网上验证用户的身份。
  • 通常状况下网站方向CA申请一个证书。CA会给网站方生成一对非对称加密的公钥私钥,公钥会作到证书里面,私钥则会给到网站方。
  • CA会先作一个“数字签名”(生成过程:明文 --> hash运算 --> 摘要 --> 私钥加密 --> 数字签名)
    • 就是将网站方的信息网站方的公钥签名算法等信息(就是Wireshark Packet 20中的数据,除了“签名值”),计算一个hash值(图中hash算法是SHA256),而后CA再用本身私钥作加密(图中公开密钥算法是RSA),最后的这个密文就是“数字签名”(也就是咱们在图中看到“encrypted”签名值)。
  • CA最后将“网站方信息”、“网站方公钥”、“签名算法”、“签名值”都作到证书里面(就是Wireshark Packet 20中的咱们看到那些数据),证书就作好了,CA会把“证书”和“网站方的私钥”给到网站方。

CA怎么验证证书是否是本身颁发的呢?以及作证书内容校验?

  • 首先浏览器(校验网站的证书)或操做系统(校验应用的证书),会在操做系统存储的系统信任的根证书里面去查找“证书颁发机构”是不是信任的。以下图系统根证书:

* 浏览器一般也会内置大多数主流权威CA的根证书。
* 若是查找不到对应的可信CA,则判断这个证书是伪造的,不可信的。(浏览器则会提醒该证书不是可信任机构颁发的,并询问是否要继续访问)
  • 若是找到对应的CA机构,则取出CA机构证书里面的公钥信息,将网站方证书中的签名值(也就是数字签名)作解密,获得网站证书信息的hash摘要A。
  • 而后将网站证书中的信息,作hash获得摘要B,比对摘要A和摘要B是否一致。若是不一致,说明网站证书中的信息被修改了。(浏览器则会提醒该证书不是可信任机构颁发的,并询问是否要继续访问)
  • 若是摘要hash一致,则说明证书中的信息未被修改,这时浏览器会比对您如今正在访问的网站与证书中网站信息是否一致,好比域名是否一致、证书是否在有效期内等。(若是出现问题,浏览器将会提醒你,并询问是否要继续访问)
  • 另外大部分浏览器也会在线校验证书,是否在有效期内(将证书序列号经过在线证书状态协议“OCSP”发送给CA作校验)。
  • 证书校验成功,最后将从证书中取出网站方的公钥,用于后面的握手签名。

4. Server Key Exchange

  • 这个步骤是密钥协商的服务端部分,最终的密钥将会用于传输数据对称加密。
  • 服务端须要发送一个Diffie-Hellman算法的公钥,和指定使用哪一种椭圆曲线多项式。
  • 咱们到Client Key Exchange的时候,再来说这个密钥协商过程。
  • 这里还有一个签名,校验这个流程的数据是否被篡改。以下图所示,客户端收到Server Key Exchange数据后,能够用上个流程中得到的证书公钥对签名值解密,得到摘要A。并将此次数据明文作SHA512的hash,得到摘要B,作比对。(这里对协商算法作签名校验,目的多是防止中间人对协商算法方式作篡改,虽然DH算法不担忧公钥在不安全的网络中传输,可是其余算法可能须要考虑被篡改的状况。因此猜想服务端密钥协商时作签名是这个目的,由于服务端这时已经肯定是DH算法了,因此客户端协商时就不须要作签名了,DH算法不须要考虑这个安全问题)
  • 发送的数据以下图示:

5. Server Hello Done

  • 服务端发送ServerHelloDone消息表示,已经发送完了密钥协商须要的消息,而且客户端能够开始进行客户端的密钥协商处理了,也就是Client Key Exchange。
  • 收到ServerHelloDone后,客户端须要确认服务器是否提供了合法的证书,而且确认服务器的ServerHello消息里面的参数是否能够接受。

6. Client Key Exchange

  • 客户端生成本身用于密钥协商的公私钥,并发送此公钥
  • 这时客户端已经知道了服务端密钥协商的公钥以及本身的公钥
  • 咱们以EC Diffie-Hellman密钥协商协议为例,来看看客户端、服务端是怎么协商出相同的密钥的(这里协商出来的是PreMasterSecret,不是最终的对称加密用到的密钥)。
  • EC Diffie-Hellman使用到一个数学难题,就是在给定的椭圆曲线上的一个点P,一个整数k,求Q=kP很容易;可是给定一个点P、Q,知道Q=kP,求整数k确实很难。
  • 服务端肯定了密钥协商算法为“EC Diffie-Hellman”,发送给客户端。如今两端都知道了使用的是哪一个曲线参数(椭圆曲线E、阶N、基点G)。
  • Server Key Change:服务端随机生成一个整数a,计算A=a*G,生成服务端公钥A,发送给客户端。
  • Client Key Change:客户端随机生成一个整数b,计算B=b*G,生成服务端公钥B,发送给服务端。
  • 客户端计算出PreMasterSecret:Q=bA=b(a*G)
  • 服务端计算出PreMasterSecret:Q'=aB=a(b*G),这两个计算结果是相等的,此时双方协商好对称密钥值。
  • 而且即便攻击者截获到双方公钥A、B,仍然没法计算出PreMasterSecret,由于攻击者须要知道随机整数a、b的其中任意一个,但是以前咱们就提到过EC Diffie-Hellman协议中,知道A、G求a是很难的。
  • 真正对称加密使用到的密钥生成(这里使用到了client、server一开始hello中传输的随机数):
    • MasterSecret = PRF(PreMasterSecret, "master secret", Client.random || Server.random)[0..47] -- 固定取前 48 字节
    • KeyBlock = PRF(MasterSecret, "key expansion", Server.random || Client.random) -- 长度为由双方肯定的密码算法套件决定
    • KeyBlock才是最终用来作对称加密的密钥块 6.3. Key Calculation

7. Client Change Cipher Spec

  • 这个过程就是告诉服务端,他已经准备好MasterSecret了,能够进行数据加密传输了。
  • 这个协议是冗余的,在TLS 1.3里面直接被删除了。

8. Client Finished

  • 这条消息是用来肯定双方的MasterSecret是否正确生成,发送的是verify_data消息。
struct { opaque verify_data[verify_data_length]; } Finished; verify_data PRF(master_secret, finished_label,Hash(handshake_messages)) [0..verify_data_length-1]; 
  • verify_data = PRF(master_secret, finished_label, Hash(handshake_messages))
    • PRF是伪随机函数(pseudorandom function,PRF)
    • master_secret是密钥协商时,计算出来的
    • finished_label:对客户端发的Finished消息来讲,固定是字符串 "client finished". 对服务器发的Finished消息来讲,固定是字符串 "server finished".
    • handshake_messages,是各端握手过程当中发送的全部消息的,类型以下:
      struct { HandshakeType msg_type; /* handshake type */ uint24 length; /* bytes in message */ select (HandshakeType) { case hello_request: HelloRequest; //HelloRequest是服务端在任什么时候候均可以发出的,告诉客户端须要从新进行握手协议,客户端随即发送新的ClientHello case client_hello: ClientHello; case server_hello: ServerHello; case certificate: Certificate;//服务端或客户端发送本身证书给客户端。 case server_key_exchange: ServerKeyExchange; case certificate_request: CertificateRequest;//服务端请求,客户端发送本身的客户端证书,给服务端作校验。这个步骤在博文中没有提到,看之后有须要再了解。 case server_hello_done: ServerHelloDone; case certificate_verify: CertificateVerify;//客户端发出,从client hello开始,一直到CertificateVerify以前的全部消息的hash加上客户端证书对应私钥的加密结果。 case client_key_exchange: ClientKeyExchange; case finished: Finished; } body; } Handshake; 
  • 但不包括ChangeCipherSpec、alerts之类的消息。而且最后一个发送Finished的一方,须要把前一个发送Finished的内容包括进去。
  • 注意这里每一个端发送本身的握手消息就能够,好比Client发送内容包括ClientHello、Certificate(有发送的话)、CertificateVerify(若是有发送的话)、ClientKeyExchange、Finished(若是是最后一方须要包含)。服务端同理。

  • 由于verify_data是加密的,我就没有在截图了,上述的字段以及说明能够查看协议文档 7.4.9. Finished

8.1. Server New Session Ticket

  • 若是服务端想使用Ticket方式存储session状态,在Server Change Cipher Spec以前就须要发送New Session Ticket消息。
  • New Session Ticket方式与Session ID方式对比:
    • SessionID方式,客户端在ClientHello的时候带着上一次SessionID过来,服务端从本身内存中查找SessionID对应的session状态,并读取session状态快速恢复。
    • SessionTicket方式,则是将session状态加密后,发送给客户端存储。客户端在ClientHello时将SessionTicket带上,服务端就将其解密,读取出里面存储的session状态信息,SessionTicket存储的信息以下:
      struct { ProtocolVersion protocol_version; //协议版本 CipherSuite cipher_suite; //加密套件类型 CompressionMethod compression_method; //压缩方法 opaque master_secret[48]; //对称密钥 ClientIdentity client_identity; //客户端ID uint32 timestamp;//ticket有效期 } StatePlaintext; 

9. Server Change Cipher Spec

  • 告诉客户端,我已经准备好进行加密传输了。

10. Server Finished

  • 与8. Client Finished的状况同样,使用对称密钥加密,最后作一次验证,肯定双方是否都准备好进行数据传输了。只是这里加密的数据还不是真正的网站内容数据,而是握手过程的数据。

11. Application Data

  • 真正的网站数据传输,可是这里的数据就是通过握手时协商好的对称密钥进行加密的了。
  • 如今咱们有KeyBlock(对称密钥块),也知道对称加密算法是AES-128-GCM 5.1. AEAD_AES_128_GCM

参考文献

相关文章
相关标签/搜索