HTTPS学习笔记:(2)通过Wireshark分析HTTPS握手过程与协议概述

TLS是一种密码学协议,用于保证两者之间的会话安全。整个SSL/TLS协议内容太多,本文只从握手,加密,套件等方面对TLS 1.2进行简要总结。

协议详细内容,可以参见:

  • RFC:http://tools.ietf.org/html/rfc5246
  • CLOUDFLARE:https://www.cloudflare.com/learning/ssl/what-is-ssl/

1. 握手(Handshake)

握手是TLS协议中最精密复杂的部分。在这个过程中,通信双方协商连接参数,并且完成身份验证。根据使用的功能的不同,整个过程通常需要交换6~10条消息。根据配置和支持的协议扩展的不同,交换过程可能有许多变种。在使用中经常可以观察到以下三种流程:

  1. 完整的握手,对服务器进行身份验证;
  2. 恢复之前的会话采用的简短握手;
  3. 对客户端和服务器都进行身份验证的握手。

1.2 完整的握手

完整的握手流程如下:

也可以参考cloudflare的流程:https://www.cloudflare.com/learning/ssl/keyless-ssl/

在Wireshark中的数据包为:

上图的流程大概可总结为:

  1. 客户端开始新的握手,并将自身支持的功能提交给服务器。
  2. 服务器选择连接参数。
  3. 服务器发送其证书链。
  4. 根据选择的密钥交换方式,服务器发送生成主密钥的额外信息。
  5. 服务器通知自己完成了协商过程。
  6. 客户端发送生成主密钥所需的额外信息。
  7. 客户端切换加密方式并通知服务器。
  8. 客户端计算发送和接收到的握手消息的MAC并发送。
  9. 服务器切换加密方式并通知客户端。
  10. 服务器计算发送和接收到的握手消息的MAC并发送。

TLS/SSL使用非对称加密提供身份认证和密钥协商(RSA、DH、ECC),使用对称加密完成信息加密(AES、DES、RC4),使用散列算法提供完整校验(MD5、SHA)

接下来将用Wireshark来分析一次真实的握手过程

1.2.1 ClientHello

ClientHello为握手的第一条消息,发送的内容有:

  • TLS版本
  • Handshake Type
  • 随机数:总共包含32字节的数据。只有28字节是随机生成的,剩余的4字
    节包含额外的信息,受客户端时钟的影响。这里标记为random_c
  • Session ID:在第一次连接时,会话ID( session D)字段是空的,这表示客户端并不希望恢复某个已存在的会话。在后续的连接中,这个字段可以保存会话的唯一标识。服务器可以借助会话ID在自己的缓存中找到对应的会话状态
  • 支持的密码套件cipher suites:客户端支持的所有密码套件组成的列表,该列表是按优先
    级顺序排列的
  • 压缩方法:客户端可以提交一个或多个支持压缩的方法。默认的压缩方法是null,代表没有压缩
  • Extensions:扩展( extension)块由任意数量的扩展组成。这些扩展会携带额外数据。

1.2.2 ServerHello

ServerHello消息的意义是将服务器选择的连接参数传送回客户端,结构与ClientHello类似。这里返回了随机数(标记为random_s),选择的套件TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,以及扩展

1.2.3 Certificate

该部分是服务器返回给客户端的证书链,如果你访问百度,会发现会有两个证书且按照等级高的在前的顺序列出来,由于样例中的证书是自己签发的且不涉及CA,所以只有一个证书。

服务器必须保证它发送的证书与选择的算法套件一致。因为并非所有套件都使用身份验证,也并非所有身份验证方法都需要证书,所以该消息是可选的。

1.2.4 ServerKeyExchange

该消息的目的是携带密钥交换的额外数据,消息内容对于不同的协商算法套

件都会存在差异。由于这里采用的是ECDHE算法,类似DH算法,所以需要密钥交换阶段,RSA算法是没有这步的。

1.2.5 ServerHelloDone

ServerHelloDone消息表明服务器已经将所有预计的握手消息发送完毕。在此之后,服务器会等待客户端发送消息

1.2.6 Client Key Exchange

ClientKeyExchange消息携带客户端为密钥交换提供的所有信息,内容随着不同的协商密码套件而不同。

如果是DH算法,则是发送交换密钥,如果是RSA则是使用服务器公钥加密随机数pre-master,与random_c、random_s共同构成协商密钥

本例中的是DH算法的的秘钥

1.2.7 Change Cipher Spec

ChangeCipherSpec消息表明发送端已取得用以生成连接参数的足够信息,已生成加密密钥,并且将切换到加密模式,此后客户端的数据均为协商密钥加密的密文。

ChangeCipherSpec不属于握手消息,它是另一种协议,只有一条消息,作为它的子协议进行实现

1.2.8 Encypted Handshake Message(finish)

为结合所有当前的通信参数信息生成一段数据,并使用协商密钥加密后的内容

1.2.9 New Session Ticket

会话标识符,解决会话缓存问题,这些数据采用一个只有服务器知道的密钥进行加密。Session Ticket由客户端进行存储,并可以在随后的一次会话中添加到 ClientHello消息的SessionTicket扩展中

1.2.10 ChangeCipherSpec,Encypted Handshake Message(finish)

与客户端发送的意义类似,代表服务器端协商的结束,与加密的开始。

1.3 会话恢复

完整的握手协议非常复杂,需要很多握手消息和两次网络往返才能开始发送客户端应用数据。会话的恢复机制可以减少网络的交互以及计算秘钥的资源开销。话恢复机制为:在一次完整协商的连接断开时,客户端和服务器都会将会话的安全参数保存一段时间。

  • 服务器希望恢复:服务器在ServerHello消息中将会话ID发回客户端。
  • 客户端希望恢复:客户端将会话ID放入ClientHello消息,然后提交。

服务器如果愿意恢复会话,就将相同的会话ID放入ServerHello消息返回,接着使用之前协商的主密钥生成一套新的密钥,再切换到加密模式,发送Finished消息。客户端收到会话已恢复的消息以后,也进行相同的操作。这样的结果是握手只需要一次网络往返。

在Wireshark中的流程为:

此时Client Hello的消息已经包含了Session ID.

2. 秘钥交换(Key Exchange)

密钥交换的主要目的是计算预主密钥( premaster secret)。这个值是组成主密钥的来源。

master_secret=PRF(pre_master_secret,"master secret",random_c,random_s)

2.1 RSA

由客户端生成一个随机值作为预主密钥, 并以服务器公钥加密 ,将其包含在ClientKeyExchange消息中,最后发送出去。服务器只需要解密这条消息

就能取出预主密钥。

优点:简单,快速

缺点:

  1. 不支持向前保密
  2. 用于加密预主密钥的服务器公钥,一般会保持多
    年不变。如果可以得到私钥,就可以恢复预主密钥,并构建相同的主密钥

2.2 ECDHE(临时椭圆曲线Diffie-Hellman:ephemeral elliptic curve Diffie-Hellman)

临时椭圆曲线Diffie-Hellman( ephemeral elliptic curve Diffie-Hellman, ECDHE)密钥交换建立在椭圆曲线加密的基础之上,其有速度快且向前兼容的优点。在TLS中, ECDHE可以与RSA或者ECDSA身份验证

一起使用。

ECDHE密钥交换由服务器发起,它选择一条椭圆曲线和公开参数(EC point), 并使用自己的私钥签名 :

然后客户端提交自己的公开参数:

现在就可以计算预主密钥。

3. 身份验证

身份验证的目的是来验证双方的身份,基础是证书包含的公钥密码(最常见的是RSA,有时也用ECDSA)。不同的秘钥交换算法,验证的方式存在一点差异:

  1. RSA秘钥交换:在RSA密钥交换的过程中,客户端生成一个随机值作为预主密钥,并以服务器公钥加密后发送出去,只有拥有证书对应私钥的服务器才能解开预主密钥
  2. ECDHE秘钥交换:服务器使用证书对应的私钥对算法参数进行加密,客户端收到参数使用证书的公钥进行解密。

4. 加密算法与类型

加密算法主要用来对应用数据进行加密,常见的算法有:3DES、 AES、 ARIA、 CAMELLIA、 RC4。目前最为广泛的是AES

TLS支持的加密类型包括以下三种:

  1. 序列加密

使用序列密码时,加密由两步组成。第一步,计算MAC值,范围包含记录序列号、标头、明文。MAC包含标头能确保未进行加密的标头不会遭受篡改。MAC包括序列号,能确保消息不被重放。第二步,加密明文和MAC,生成密文。

  1. 分组加密:

使用分组密码时,加密会涉及更多内容,因为需要为分组加密的特性准备解决方案。具体来 说,需要以下几个步骤:

1. 计算序列号、标头和明文的MAC。

2. 构造填充,确认加密前的数据长度是分组大小(通常16字节)的整数倍。

3. 生成一个长度与分组大小一致的不可预期的初始向量(initialization vector,IV)。IV能保证加密是不确定的。

4. 使用CBC分组模式加密明文、MAC和填充。

5 将IV和密文一起发送。

操作流程如下:

  1. 以验证加密

已验证的密码将加密和完整性验证合二为一,全名是使用关联数据的已验证加密。已验证加密被认为是当前TLS中可用的加密模式中最好的一种,因为它可以避免MAC-then-

encrypt方式带来的问题。

虽然TLS当前定义了基于GCM和CCM块模式的已验证套件,实际上仅支持GCM套件。

操作流程如下:

5. 重新协商

大部分TLS连接都以握手作为起点,经过应用数据的交换,最后关闭会话。但如果请求重新协 商,就会发起一次新的握手,对新的连接安全参数达成一致。该功能在以下场景很有用:

  • 客户端证书:客户端证书并不常用,但因为它可以提供双因素身份验证,所以还是有一些网站在使用它
  • 改变加密强度: 当网站加密刚刚出现(而且是CPU密集的)的时候,经常可以发现网站将加密配成两个级别。你可以默认使用比较弱的加密,而在特定区域使用强加密。当尝试进入网站中更安全的子区域时,服务器将请求更强的安全性。

6. 警报协议

警报的目的是以简单的通知机制告知对端通信出现异常状况。它通常会携带close_notify异常,在连接关闭时使用,报告错误。警报非常简单,只有两个字段:

  • level:表示警报的严重程度,可取值warning或者fatal
  • description:表示警报代码

7. 秘钥操作

在TLS中,伪随机函数(pseudorandom function,PRF)用于生成任意数量的伪随机数据,其中主密钥,最终秘钥都依赖伪随机函数

7.1 预主秘钥(premaster secrets)

密钥交换过程的输出是预主密钥。不同的秘钥交换算法采取的方式有所不同:

  • RSA:RSA密钥交换的过程十分直接。客户端生成预主密钥(46字节随机数),使用服务器公钥对其加密,将其包含在ClientKeyExchange消息发送出去

  • ECDHE:使用客户端以及服务器端的dh参数生成预主秘钥

7.2 主秘钥

对预主密钥进行进一步加工,就是使用PRF生成48字节(384位)主密钥:

master_secret = PRF(pre_master_secret, "master secret",
ClientHello.random + ServerHello.random)

由于PRF输出的长度是固定的,所以即使预主密钥长度可能不同,最终结果的长度也是一致的。

同时,因为客户端和服务器的随机字段被用作种子,所以主密钥实际上也是随机的.

7.3 秘钥

最终用来加密数据的秘钥生成方式如下:

key_block = PRF(master_secret, “key expansion”, server_random + client_random)

由于生成key_block的参数,在server以及client上都是一致的,所以两方生成的key_block也是一致的。

key_block块分为六个密钥:

  • 两个MAC密钥:已验证加密的套件不使用MAC密钥,例如GCM。
  • 两个加密密钥:加密数据
  • 两个初始向量:只在必要时生成;序列密码不会使用IV。

8. 密码套件

密码套件定义了秘钥交换,身份验证,加密算法,加密模式等方式。密码套件的构成如下:

密码套件并未完全掌控其安全参数。它们只是定义了最关键的身份验证和密钥交换算法,而 对这些算法的实际参数并没有控制能力(比如密钥和参数强度)。

对于身份验证,其强度主要依靠证书,更确切地说是证书中的密钥长度和签名算法。RSA密 钥交换的强度也依赖证书。可以为DHE和ECDHE密钥交换配置不同的强度,这通常是在服务器 级别的配置中完成的

9. 发展历史

SSL3(1995年末发布)->TLS 1.0(1999年初)->TLS 1.1(2006.4发布) ->TLS1.2(2008年8月发布,目前使用较广的版本)

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章