一、相关知识
(一) 密钥交换算法
TLS 中密钥交换算法有6种:无效(没有密钥交换)、RSA、匿名Diffie-Hellman、暂时Diffie-Hellman、固定Diffie-Hellman、Fortezza。
RSA 和 ECDHE 是最常用的两个密钥交换算法。
RSA密钥协商
- Client 发送 Server 的 "Client Hello" 报文中带有随机数 Random_1;
- Server 发送 Client 的 "Server Hello" 报文中带有随机数 Random_2;
- Client 用过 RSA 算法随机生成 Pre-Master Secret,并且用服务器公钥加密,包含在"Client Key Exchange" 中发送给 Server;
- Client 和 Server 通过 Random_1、Random_2 和 Pre-Master Secret 通过伪随机数函数 PRF 生成 Master Secret。
ECDHE密钥协商
- Client 发送 Server 的 "Client Hello" 报文中带有随机数 Random_1,同时包括两个 Extension "elliptic_curves" 和 "ec_point_formats";
- Server 发送 Client 的 "Server Hello",包含一个随机数 Random_2及 ECC 扩展;
- Server 发送 Client 证书;
- Server 生成 ECDH 临时公钥,发送 "Server Key Exchange",包含三部分重要内容:ECC 相关的参数、服务器生成的 ECDH 临时公钥、ECC 参数和公钥生成的签名值。
- Client 验证证书合法性,获取服务器生成的 ECHD 临时公钥计算出正式的对称加密密钥;
- Client 生成客户端 ECHD 临时公钥,发送 "Client Key Exchange",与上面不同的是,这个 ECHD 临时公钥不需要加密;
- Server 收到客户端 ECHD 临时公钥后计算出正式的对称加密密钥;
(二) X.509
其实数字证书并没有一个全球统一的标准,但是现在大多数证书都使用着一个标准的形式X.509 v3。下面列表包括了证书的主要字段:
字段 | 描述 |
---|---|
版本 version | 这个证书的 X.509 证书版本号。现在使用的通常都是版本 v3 |
序列号 serialNumber | 证书颁发机构(CA)生成的唯一整数。CA 生成的每个证书都要有一个唯一的序列号 |
签名算法 ID signature | 签名所使用的加密算法。例如,“用 RSA 加密的 MD2 摘要” |
证书颁发者 issuer | 发布并签署这个证书的组织名称,以 X.500 格式表示 |
有效期 validity | 此证书何时有效,由一个起始日期(Not Valid Before)和一个结束日期(Not Valid After)来表示 |
对象名称 subject | 证书中描述的实体,比如一个人或一个组织。对象名称是以 X.500 格式 表示的 |
对象的公开密钥信息 subjectPublicKeyInfo | 证书对象的公开密钥,公开密钥使用的算法,以及所有附加参数 |
证书的颁发机构签名 encrypted | 证书颁发机构用指定的签名算法对上述所有字段进行的数字签名 |
不清晰的话通过抓包一个真实的证书来对比一下
版本 version: v3
序列号 serialNumber: 0x040000000001444ef04247
签名算法ID signature: Algorithm Id: 1.2.840.113549.1.1.11 (sha256WithRSAEncryption) // 用RSA加密的Sha256摘要
...
(三) 数字证书的生成
如果我是一家公司,我需要申请受信任的证书颁发机构给我认证,需要提供哪些信息。
- 你公司的信息,包括地区、公司或组织名称等;
- 你需要生成一个自己的公钥;
- 颁发机构会将这些信息通过散列算法计算出一个摘要,用颁发机构的私钥进行加密(也就是签名);
- 一个属于你公司的数字证书就生成了。
Q&A
- 受信任的颁发机构的根证书是怎么来的?
A: 颁发机构没有上一级颁发机构,他们的数字签名是通过自己的私钥来签名的。
- 一定要找收信任的颁发机构签名证书吗?
A: 不一定,也可以自己给自己签发一个证书,但是由于浏览器只内置了受信任的颁发机构的根证书,如果自己作为一个颁发机构给自己签名,浏览器会弹出不信任,但是整个传输过程仍然是安全的。举个例子:12306就是这么干的。
(四) 信任链
数字证书的颁发其实就是上一个机构A用A的私钥为待颁发的机构的数字证书签名,所以信任链的概念也比较明显。
假如A是受信任的颁发机构,B的证书是由A颁发的,而B为C的数字证书签了名,当服务器C请求浏览器安全传输时,因为A是被浏览器信任的,而A信任了B,B又信任了C,所以浏览器是信任C的。
Q&A
- C请求安全传输时,浏览器如何验证它的证书?
A: 因为浏览器只内置了受信任的颁发机构A的根证书,所以C需要带上B的数字证书,否则验证无法通过。
- 信任链是否可以无限长?
A: 不是,信任链有最大支持长度。
二、HTTPS 抓包分析
首先我们来一张图看完整个 SSL/TLS 握手过程,后面一步一步地抓包分析。
以访问 百度 为例子,用 Wireshark 抓取 Https 包分析,本次抓包先清除了浏览器缓存。
(一) Client -> Server
第一步客户端向服务器发送 "Client Hello" 信息,其中包括了一些字段重点介绍一下:
Client Hello
- Version 协议版本号
说明了使用的 SSL/TLS 协议版本号。
- Random 随机数
随机数的前4个字节是当前的协调世界时钟的 Unix 时间戳,后面紧接28个字节的随机数,总共32个字节。
- Session ID 会话标识
作用是客户端和服务器短时间断连后,可以帮助找回之前的会话,而不需要重新进行握手。首次连接时该字段为空。
- Cipher Suite 密码套件
告知服务器当前客户端所支持的密码算法的列表,可见图中的列表列举了16种密码算法方式。
- Compression method 压缩方法
告知服务器当前客户端支持的压缩方法,一般不在 TLS层压缩,图中为null。
- Extension 扩展
图中列出了很多扩展,我选择几个重点说明,以后学习到新的我也会补充:
- server_name
指示当前访问的域名,服务器可能需要部署多个独立的网站,但是IP地址却是同一个,这样无法正确找到对应的证书,所以需要指示出当前请求的域名,服务器匹配正确的证书。
- sessionTicket TLS (图中未出现)
它的出现主要是为了解决 Session ID 在服务器端缓存的压力,Session Ticket 保存在客户端并且由服务器密钥进行加密。如果客户端支持Session Ticket,在 TLS 握手的最后一步中服务器将包含一个 "New Session Ticket" 信息。
- Application Layer Protocol Negotiation (ALPN 应用层协议协商)
在 TLS 握手期间,客户端和服务器商议使用的应用层协议,如果服务器不支持客户端要求的协议则中止连接。
- signature algorithms 签名算法
指明签名可以使用的哈希算法。
总得而言,"Client Hello" 就是客户端和服务器在进行协商,如果服务器能接受,则继续;不能接受,则中止握手。
(二) Server -> Client
如果报文有 Session ID,服务器通过对 ID 进行校验,如果成功则直接恢复之前的会话。如果没有 ID,服务器将保存客户端生成的随机数,在密码套件中选择使用的密码套件。
第二步,服务器向客户端发送 "Server Hello" 信息,其中包括了:
- 随机数 Random
服务器根据相同的生成规则生成一个随机数。
- 密码套件 Cipher Suite
从客户端的套件列表中选取一个套件并告知客户端。
紧接着发送 Certificate 证书和 "Server Hello Done"信息:
Server Key Exchange
服务器密钥交换。
Server Hello Done
表示 SSL/TLS 握手结束。
(三) Client 校验证书合法性
- 判断证书是否在有效期内;
- 签名颁发者可信度检测,沿着信任链向根证书验证该证书的合法性,直到找到一个客户端信任的证书颁发机构,否则验证失败;
- 通过用颁发机构的公钥解密签名,与证书的散列比较,如果不相等,验证失败;
- 站点身份检测,为防止服务器复制其他人的证书,大部分浏览器都会去验证证书中的域名与它们所对话的服务器的域名是否匹配。
(四) Client -> Server
Client Key Exchange
客户端密钥交换。
Change Clipher Spec
不管是DH算法还是RSA算法,此时客户端都可以计算出正确的Master Secret(加密传输所使用的对称加密秘钥),所以 "Change Clipher Spec" 是客户端告知服务器开始使用加密方式发送报文和 MAC 计算。
Encrypted Handshake Message (Finished)
对之前握手的所有信息用 Master Secret 进行加密后传输,防止被篡改,同时验证加密传输是否可用。
(五) Server -> Client
服务器收到客户端报文后计算出相同的 Master Secret,发送"Change Clipher Spec" 和 "Encrypted Handshake Message"。
三、再次抓包
间隔一段时间,对百度首页再次抓包
可以发现 Session ID 字段有了一个32字节长度的值,再看看整个 SSL/TLS 握手过程发现了什么变化:
握手过程减少了不少,可见 Session ID 的存在使得客户端和服务器恢复了之前的会话,它们之间采用了之前的加密密钥继续进行加密传输。
四、补充
(一) 密码套件分析
从抓包结果,解读一下密码套件的含义:
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
- 基于TLS协议
- 用ECDHE_RSA做密钥交换算法
- 用AES_128_CBC做内容的对称加密算法
- 用SHA256做MAC算法
算法种类
- 密钥交换算法,用于决定客户端与服务器之间在握手的过程中如何认证,用到的算法包括RSA,Diffie-Hellman,ECDH,PSK等
- 对称加密算法,用于加密消息流,该名称后通常会带有两个数字,分别表示密钥的长度和初始向量的长度,比如DES 56/56, RC2 56/128, RC4 128/128, AES 128/128, AES 256/256
- 报文认证信息码(MAC)算法,用于创建报文摘要,确保消息的完整性,算法包括MD5,SHA等。
- PRF(伪随机数函数)用于生成"Master Secret"。
(二) MAC
TLS协议还提供了它自己的消息分片机制,且采用消息认证码(MAC)对每一个分片消息进行签名。MAC算法是一个单向的哈希加密函数(一个非常高效的校验码),HASH函数密钥由两端进行协商。每当一个TLS记录被发送,生成的MAC值,将附加在该消息中,接收端采用相同的方法计算和验证所发送的MAC值,以确保消息的完整性和真实性。
(三) SNI
SNI 全称Server Name Indication
,如果服务器需要部署多个独立的网站,每个与自己的TLS证书,但使用同一个IP地址。
为了解决上述问题,SNI 扩展被引入到 TLS 协议中,它允许客户端在握手开始指示他想要连接的主机名。服务器检查SNI主机名,选择适当的证书,并继续握手。
TLS,HTTP和专用IP
(四) TLS压缩
一个鲜为人知的TLS特性就是在其纪录协议中已经内置支持无损数据压缩:压缩算法在TLS握手过程中协商,数据在加密应用之前进行压缩。然而,在实际应用中,你应该在你的服务器上禁用TLS压缩,有以下几个原因:
- "CRIME"攻击,在2012年被公布,利用TLS压缩来恢复身份验证的Cookie,并允许攻击者进行会话劫持;
- TLS压缩属于传输层压缩,他无法感知数据内容,他将去重复压缩已压缩的数据(比如图片,视频等)。重复压缩会同时在服务器和客户端浪费CPU时间。
另外,安全漏洞的影响也是相当的严重,因此需要禁用压缩TLS。在实际应用中,大多数的浏览器都是禁用TLS压缩的,不过,你应该明确的在您的服务器上明确的禁用,以保护您的用户。
相反,我们不应该依赖于TLS的压缩,而是应该在应用层配置Gzip,使所有文本型资源采用gzip方式传输,而对其他格式如图像,视频和音频应该去选取最佳的压缩格式。