SSL/TLS协议详解(下)——TLS握手协议


本文翻译自:https://www.wst.space/ssl-part-4-tls-handshake-protocol/


  在博客系列的第2部分中,对证书颁发机构进行了深入的讨论.在这篇文章中,将会探索整个SSL/TLS握手过程,在此之前,先简述下最后这块内容的关键要点:

  • TLS适用于对称密钥
  • 对称密钥可以通过安全密钥交换算法共享
  • 如果请求被截获,密钥交换可能会被欺骗
  • 使用数字签名进行身份验证
  • 证书颁发机构和信任链。

  在这篇文章中,使用WireShark的工具来查看网络流量,我个人使用的是Linux(Ubuntu 16.04)系统,可以使用以下命令轻松安装WireShark:

$sudo apt install wireshark

  以sudo的权限打开WireShark并选择提供互联网连接的接口,我这里是eth0,然后点击WireShark右上角的“开始捕获数据包”按钮,Wireshark将立即开始抓取通过机器的所有流量。现在我们从浏览器中加载github.com。Github使用TLS进行所有通信,将重新定向到https并加载。现在关闭浏览器,看看WireShark抓到了什么。

DNS解析

  这并不是TLS的一部分,但我们在WireShark中看到了它。

  我已将Google DNS设置为我的DNS服务器,它的地址是8.8.8.8,在图像中可以看到请求已发送到8.8.8.8查询github.com的A记录,也就是我们想要连接的Github的IP地址。

  DNS服务器使用github.com的IP响应为192.30.253.113,蓝色表示选择显示相应的部分,现在,浏览器已获取了将要用来连接服务器的目标IP。

发起TLS握手

  解析IP后,浏览器将通过http请求页面,如果服务器支持TLS,那么它将发送协议升级请求来响应浏览器,这个新的地址https://github.com ,将使用端口号443来指定,随后浏览器将启动TLS握手请求。大多数现代浏览器都存有与Web服务器的最后一次连接的记录,如果最后一次连接是通过https进行的,那么下次浏览器将自动启动https请求而无需等待服务器。
TLS握手分为以下几个步骤:

  • 客户端发送Hello报文
  • 服务器接收Hello报文
  • 共享证书和服务器密钥交换
  • 更改密码规范
  • 加密握手

客户端发送Hello报文

  从这里开始,我将会重点讨论图片中标记为蓝色的主题,Client发送的Hello报文如下图所示。

  我们知道TLS是在TCP之上实现的协议,TLS本身是一层协议并且它的底层叫做记录协议(Record protocol),这意味着所有数据都被记录。典型的记录格式如下:

HH V1:V2 L1:L2 data
  • HH是单个字节,表示记录中的数据类型。共定义了四种类型:change_cipher_spec(20),alert(21),handshake(22)和application_data(23)。
  • V1:V2是协议版本,用两个以上的字节表示。对于当前定义的所有版本,V1的值为0x03,而对于SSLv3,V2的值为0x00,对于TLS 1.0为0x01,对于TLS 1.1为0x02,对于TLS 1.2为0x03。
  • L1:L2是数据的长度,以字节为单位(使用big-endian约定:长度为256 * L1 + L2),数据的总长度不能超过18432字节,但实际上它无法达到这个值。

  在图中,可以看出内容类型是Handshake,TLS版本1.0,数据长度为512.真实数据位于名为 Handshake Protocol:Client Hello的下拉列表中。我们继续观察下Client Hello中共享的数据。

客户端发送Hello报文的内容

  浏览器与服务器共享以下详细信息

客户端版本

  按优先顺序列出的客户端支持的协议版本,首选客户希望支持的最新协议版本。

客户端的随机数

  一个32字节的数据,其中前4个字节表示epoch格式的当前日期时间。纪元时间是自1970年1月1日以来的秒数。其余28个字节由加密强随机数生成器生成(例如,Linux中的/dev/urandom),客户端随机会在后面用到,请先记住这点。

会话id(Session id)

  如果客户端第一次连接到服务器,那么这个字段就会保持为空。在上图中,您可以看到Session id正在给服务器发送东西,之所以会发生这种情况是由于我之前是通过https连接到github.com的,在此期间,服务器将使用Session id映射对称密钥,并将Session id存储在客户端浏览器中,为映射设置一个时间限。如果浏览器将来连接到同一台服务器(当然要在时间限到期之前),它将发送Session id,服务器将对映射的Session进行验证,并使用以前用过的对称密钥来恢复Session,这种情况下,就不需要完全握手。

密码套件

  客户端还将发送自己已经知道的密码套件列表,这个是由客户按优先顺序排列的,但完全由服务器来决定发送与否。TLS中使用的密码套件有一种标准格式。

我们从列表中用一个例子来进行分析.

Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
  • TLS:指使用的协议是TLS
  • ECDHE:密钥交换算法
  • ECDSA:签名或验证算法
  • AES_128_GCM:称为批量加密算法。对称密钥加密算法是AES,密钥长度为128位,AES是块密码,也就是对输入的纯文本用固定长度的块来进行加密,加密后的每个块按再顺序发送,最后按类似的方式来进行解密。按标准规定,AES块固定长度为128位,但是输入的明文不要求必须是128的倍数,所以我们可能需要对最后一个块中进行填充,使其为固定的长度128位。除此之外,为了提高平均信息量,通常在加密之前会添加一些随机的比特到明文中,我们称为初始化矢量(IV)。有很多算法都可以在块上添加IV实现填充。在我们的例子Galois/Counter Mode(GCM)中用到过。或许详细解释GCM模式会使事情变得复杂,可见这并不是一个好主意。
    SHA256:消息验证代码(MAC)算法。我们将详细讨论MAC。

压缩数据

  为了减少带宽,可以进行压缩。但从成功攻击TLS的事例中来看,其中使用压缩时的攻击可以捕获到用HTTP头发送的参数,这个攻击可以劫持Cookie,这个漏洞我们称为CRIME。从TLS 1.3开始,协议就禁用了TLS压缩。

扩展名

  其他参数(如服务器名称,填充,支持的签名算法等)可以作为扩展名使用,我们可以任意对用作扩展名的内容研究一番。

  这些是客户端问候的一部分,如果已收到客户端问候,接下来就是服务器的确认,服务器将发送服务器问候。

服务器接收Hello报文

  收到客户端问候之后服务器必须发送服务器问候信息,服务器会检查指定诸如TLS版本和算法的客户端问候的条件,如果服务器接受并支持所有条件,它将发送其证书以及其他详细信息,否则,服务器将发送握手失败消息。

图中,我们可以看到服务器响应0x0303表示服务器同意使用TLS 1.2,我们来检查一下服务器问候中的记录。

服务器接收Hello报文的内容

  服务器问候消息包含以下信息。

点击收藏 | 2 关注 | 1
登录 后跟帖