SSL详解

Java基础

浏览数:318

2019-7-28

SSL

1.整体结构

SSL是一个介于HTTP协议与TCP之间的一个可选层,其位置大致如下

SSL:(Secure Socket Layer,安全套接字层),为Netscape所研发,用以保障在Internet上数据传输之安全,利用数据加密(Encryption)技术,可确保数据在网络上之传输过程中不会被截取。当前版本为3.0。它已被广泛地用于Web浏览器与服务器之间的身份认证和加密数据传输。

SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。

SSL协议可分为两层:

  • SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。
  • SSL记录协议(SSL Record Protocol):

TLS:(Transport Layer Security,传输层安全协议),用于两个应用程序之间提供保密性和数据完整性。
TLS 1.0是IETF(Internet Engineering Task Force,Internet工程任务组)制定的一种新的协议,它建立在SSL 3.0协议规范之上,是SSL 3.0的后续版本,可以理解为SSL 3.1,它是写入了 RFC 的。

该协议由两层组成:

  • TLS 握手协议(TLS Handshake):1) 握手协议;2)密码规格变更协议;3)警告协议; 4)应用数据协议
  • TLS 记录协议(TLS Record)较低的层为 TLS 记录协议,它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持,定义了传输的格式;
    • 将消息分割为多个片段;
    • 对每个片段进行压缩
    • 加上片段编号(防止重放攻击)计算消息验证码MAC值(保证数据完整性),追加在压缩片段
    • 对称密码加密;
    • 加上数据类型、版本号、压缩后的长度组成的报头, 就是最终的报文数据;

SSL/TLS协议提供的服务主要有:

  1. 认证用户和服务器,确保数据发送到正确的客户机和服务器;
  2. 加密数据以防止数据中途被窃取;
  3. 维护数据的完整性,确保数据在传输过程中不被改变

SSL 加密套件

加密套件(CipherList)是指在ssl通信中,服务器和客户端所使用的加密算法的组合。

  • 密钥交换 用于决定客户端与服务器之间在握手的过程中如何认证。使用非对称加密算法来生成会话密钥,因为非对称算法不会将重要数据在通信中传输用到的算法包括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”

    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
    从其名字可知,它是:
    基于TLS协议的;
    使用ECDHE作为密钥交换算法ECDHE默认为ECDHE_RSA;
    加密算法是AES(密钥和初始向量的长度都是256);
    MAC算法(这里就是哈希算法)是SHA。

2.TLS与SSL的差异

  1. 版本号 : TLS记录格式与SSL记录格式相同,但版本号的值不同,TLS的版本1.0使用的版本号为SSLv3.1。
  2. 报文鉴别码
  3. 伪随机函数
  4. 报警代码
  5. 密文族和客户证书
  6. certificate_verify和finished消息
  7. 加密计算
  8. 填充

3.TLS主要增强内容

TLS的主要增强内容

TLS的主要目标是使SSL更安全,并使协议的规范更精确和完善。TLS 在SSL v3.0 的基础上,提供了以下增强内容:

  1. 更安全的MAC算法
  2. 更严密的警报
  3. “灰色区域”规范的更明确的定义

4. 密钥协商过程——TLS握手

由于非对称加密的速度比较慢,所以它一般用于密钥交换,双方通过公钥算法协商出一份密钥,然后通过对称加密来通信,当然,为了保证数据的完整性,在加密前要先经过HMAC的处理。

SSL缺省只进行server端的认证,客户端的认证是可选的

4.1 客户端发出请求(ClientHello)

  1. 支持的协议版本,比如TLS 1.0版
  2. 一个客户端生成的随机数random_C,稍后用于生成”对话密钥”
  3. 支持的加密方法,比如RSA公钥加密(密码套件)
  4. 支持的压缩方法
  5. Session id

4.2 服务器回应(SeverHello)

  1. 确认使用的加密通信协议版本,比如TLS 1.0版本。如果浏览器与服务器支持的版本不一致,服务器关闭加密通信
  2. 一个服务器生成的随机数random_S,稍后用于生成”对话密钥”
  3. 确认使用的加密方法,比如RSA公钥加密
  4. 服务器证书

:在服务端向客户端发送的证书中没有提供足够的信息(证书公钥)的时候,如基于 DH 的证书,公钥不被证书中包含,需要单独发送,还可以向客户端发送一个 客户端握手server_key _exchange,此外,对于非常重要的保密数据,服务端还需要对客户端进行验证,以保证数据传送给了安全的合法的客户端。服务端可以向客户端发出 Cerficate Request 消息,要求客户端发送证书对客户端的合法性进行验证。消息包括:

  • 客户端可以提供的证书类型;
  • 服务器端可以理解的认证机构名称清单(可以是root CA或者subordinate CA。如果服务器配置了trust keystore, 这里会列出所有在trust keystore中的证书的distinguished name),

最后服务端会发送一个Server Hello Done消息给客户端,表示Server Hello消息结束了。

4.3 客户端回应

1.certificate(可选):客户端证书

2.Client Key Exchange一个随机数。该随机数用服务器公钥加密,防止被窃听(产生一个48个字节的Key,客户端使用一些加密算法(例如:RSA, Diffie-Hellman)产生一个48个字节的PreMaster Secret.

此时客户端已经获取全部的计算协商密钥需要的信息:两个明文随机数 random_C 和 random_S 与自己计算产生的 Pre-master,计算得到协商密钥:

   master_secret =PRF(pre_master_secret, "master secret", random_C +random_S)

   pre_master_secret就是我们之前传送的随机密码串,”mastersecret”是一串ASCII码,再加上之前提到的random1和random2。PRF是在规范中约定的伪随机函数,它将密钥、ASCII码标签、哈希值整合在一起。各有一半的参数分别使用MD5和SHA-1获取哈希值。这是一种十分明智的做法,即使是想要单单破解相对简单MD5和SHA-1也不是那么容易的事情。而且这个函数会将返回值传给自身直至迭代到我们需要的位数
     客户端得到master_secret后,根据协议约定,我们需要利用PRF生成这个会话中所需要的各种密钥,称之为“密钥块”(key block)

3.certificate_verify:发送使用客户端证书给到这一步为止收到和发送的所有握手消息签名结果(包括master secret)。(向服务器证明自己的确持有客户端证书私钥。

4.ChangeCipherSpec 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送(ChangeCipherSpec是一个独立的协议,体现在数据包中就是一个字节的数据,用于告知服务端,客户端已经切换到之前协商好的加密套件(Cipher Suite)的状态,准备使用之前协商好的加密套件加密数据并传输了

5.客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供服务器校验(使用HMAC算法计算收到和发送的所有握手消息的摘要,然后通过RFC5246中定义的一个伪函数PRF计算出结果,加密后发送。此数据是为了在正式传输应用数据之前对刚刚握手建立起来的加解密通道进行验证。)

4.4 服务器的最后回应(Server Finish)

  1. 使用私钥解密加密的Pre-master数据,基于之前交换的两个明文随机数 random_C 和 random_S,计算得到协商密钥:enc_key=Fuc(random_C, random_S, Pre-Master);
  2. 计算之前所有接收信息的 hash 值,然后解密客户端发送的 encrypted_handshake_message,验证数据和密钥正确性;
  3. 发送一个 ChangeCipherSpec(告知客户端已经切换到协商过的加密套件状态,准备使用加密套件和 Session Secret加密数据了)
  4. 服务端也会使用 Session Secret 加密一段 Finish 消息发送给客户端,以验证之前通过握手建立起来的加解密通道是否成功。

根据之前的握手信息,如果客户端和服务端都能对Finish信息进行正常加解密且消息正确的被验证,则说明握手通道已经建立成功,接下来,双方可以使用上面产生的Session Secret对数据进行加密传输了。

4.5 几个secret

1. PreMaster secret

PreMaster Secret是在客户端使用RSA或者Diffie-Hellman等加密算法生成的。它将用来跟服务端和客户端在Hello阶段产生的随机数结合在一起生成 Master Secret。PreMaster secret前两个字节是TLS的版本号,这是一个比较重要的用来核对握手数据的版本号。服务端需要对密文中解密出来对的PreMaster版本号跟之前Client Hello阶段的版本号进行对比,如果版本号变低,则说明被串改,则立即停止发送任何消息

2. Master secret
上面已经提到,由于服务端和客户端都有一份相同的PreMaster secret和随机数,这个随机数将作为后面产生Master secret的种子,结合PreMaster secret,客户端和服务端将计算出同样的Master secret。

Master secret是有系列的hash值组成的,它将作为数据加解密相关的secret的 Key Material 的一部分。Key Material最终解析出来的数据如下:

  • write MAC key,就是session secret或者说是session key 用来计算HMAC。
  • Client write MAC key是客户端发数据的session secret ,
  • Server write MAC secret是服务端发送数据的session key 用来加密消息。
  • MAC(Message Authentication Code),是一个数字签名,用来验证数据的完整性,可以检测到数据是否被串改。

基于ECDHE的SSL


(1):客户端随机生成随机值Ra,计算Pa(x, y) = Ra * Q(x, y),Q(x, y)为全世界公认的某个椭圆曲线算法的基点。将Pa(x, y)发送至服务器。

(2):服务器随机生成随机值Rb,计算Pb(x,y) – Rb * Q(x, y)。将Pb(x, y)发送至客户端。

(3):客户端计算Sa(x, y) = Ra * Pb(x, y);服务器计算Sb(x, y) = Rb *Pa(x, y)

(4):算法保证了Sa = Sb = S,提取其中的S的x向量作为密钥(预主密钥)。

密钥协商抓包

重要信息
    1:指明自己使用的椭圆曲线(一般根据客户端的拓展中supported_groups中的选择椭圆曲线算法)。

    2:公钥。服务器本地计算一个大数(BIGNUM),乘上曲线的base point,得到一个新的point,这个point就是公钥,用04+x+y的格式组织起来。04表示unconpressed point,和客户端的ec_point_formats有关。

    3:签名。和RSA握手不通,RSA情况下, 只要能值正常协商密钥,那么必然服务器端有证书对应的私钥,也间接表明了服务器拥有该证书。DHE/ECDHE不同,证书对应的私钥并不参与密钥协商,如果要证明服务器拥有证书,则必然有签名的操作(就像双向认证的情况下,客户端需要发送certificate verify)。被签名数据从curve type起,至point的y为止。对于TLS1.2,签名前使用client hello拓展中提供的摘要算法。TLS1.0和TLS1.1,如果本地证书是ECC证书,即若要使用ECDSA签名,这种摘要算法为SHA1,其他的情况摘要算法为md5+sha1。
计算摘要之后就调用RSA或者ECDSA进行签名。注意的是,TLS1.2时要带上2字节的“Signature Hash Algorithm”。
———————

ECDHE与ECDH的区别

字面少了一个E,E代表了“临时”,即在握手流程中,作为服务器端,ECDH少了一步计算Pb的过程,Pb用证书中的公钥代替,而证书对应的私钥就是Xb。由此可见,使用ECDH密钥交换算法,服务器必须采用ECC证书;服务器不发送server key exchange报文,因为发送certificate报文时,证书本身就包含了Pb信息。

ECDHE(DHE)算法属于DH类密钥交换算法, 私钥不参与密钥的协商,故即使私钥泄漏,客户端和服务器之间加密的报文都无法被解密,这叫 前向安全(forward secrity)。由于ECDHE每条会话都重新计算一个密钥(Ra、Rb),故一条会话被解密后,其他会话仍旧安全。

5.应用数据传输

在所有的握手阶段都完成之后,就可以开始传送应用数据了。应用数据在传输之前,首先要附加上MAC secret,然后再对这个数据包使用write encryption key进行加密。在服务端收到密文之后,使用Client write encryption key进行解密,客户端收到服务端的数据之后使用Server write encryption key进行解密,然后使用各自的write MAC key对数据的完整性包括是否被串改进行验证。

6.会话缓存握手过程

6.1概述

为了加快建立握手的速度,减少协议带来的性能降低和资源消耗(具体分析在后文),TLS 协议有两类会话缓存机制:

  • 会话标识 session ID: 由服务器端支持,协议中的标准字段,因此基本所有服务器都支持,服务器端保存会话ID以及协商的通信信息,Nginx 中1M 内存约可以保存4000个 session ID 机器相关信息,占用服务器资源较多;
  • 会话记录 session ticket :t需要服务器和客户端都支持,属于一个扩展字段,支持范围约60%(无可靠统计与来源),将协商的通信信息加密之后发送给客户端保存,密钥只有服务器知道,占用服务器资源很少。
  • 二者对比,主要是保存协商信息的位置与方式不同,类似与 http 中的 session 与 cookie。二者都存在的情况下,(nginx 实现)优先使用 session_ticket。

6.2 会话标识 session ID

​ (a) 如果客户端和服务器之间曾经建立了连接,服务器会在握手成功后返回 session ID,并保存对应的通信参数在服务器中;
(b) 如果客户端再次需要和该服务器建立连接,则在 client_hello 中 session ID 中携带记录的信息,发送给服务器;
(c) 服务器根据收到的 session ID 检索缓存记录,如果没有检索到货缓存过期,则按照正常的握手过程进行;
(d) 如果检索到对应的缓存记录,则返回 change_cipher_spec 与 encrypted_handshake_message 信息,两个信息作用类似,encrypted_handshake_message 是到当前的通信参数与 master_secret的hash 值;
(f) 如果客户端能够验证通过服务器加密数据,则客户端同样发送 change_cipher_spec 与 encrypted_handshake_message 信息;
(g) 服务器验证数据通过,则握手建立成功,开始进行正常的加密数据通信。

6.3 会话记录 session ticket

​ (a) 如果客户端和服务器之间曾经建立了连接,服务器会在 new_session_ticket 数据中携带加密的 session_ticket 信息,客户端保存;
(b) 如果客户端再次需要和该服务器建立连接,则在 client_hello 中扩展字段 session_ticket 中携带加密信息,一起发送给服务器;
(c) 服务器解密 sesssion_ticket 数据,如果能够解密失败,则按照正常的握手过程进行;
(d) 如果解密成功,则返回 change_cipher_spec 与 encrypted_handshake_message 信息,两个信息作用与 session ID 中类似;
(f)如果客户端能够验证通过服务器加密数据,则客户端同样发送 change_cipher_spec与encrypted_handshake_message 信息;
(g) 服务器验证数据通过,则握手建立成功,开始进行正常的加密数据通信。

HMAC

我们假设H是一个将数据块用一个基本的迭代压缩函数来加密的散列函数。

我们用B来表示数据块的字长。(以上说提到的散列函数的分割数据块字长B=64),

用L来表示散列函数的输出数据字长(MD5中L=16(128位),SHA—1中L=20(160位))。

鉴别密钥的长度可以是小于等于数据块字长的任何正整数值。

应用程序中使用的密钥长度若是比B大,则首先用使用散列函数H作用于它,然后用H输出的L长度字符串作为在HMAC中实际使用的密钥。

一般情况下,推荐的最小密钥K长度是L个字长。(与H的输出数据长度相等)。

H( K XOR opad, H(K XOR ipad, text))

即为以下步骤:

(1) 在密钥K后面添加0来创建一个子长为B的字符串。

(例如,如果K的字长是20字节,B=64字节,则K后会加入44个零字节0x00)

(2) 将上一步生成的B字长的字符串与ipad做异或运算。

(3) 将数据流text填充至第二步的结果字符串中。

(4) 用H作用于第三步生成的数据流。

(5) 将第一步生成的B字长字符串与opad做异或运算。

(6) 再将第四步的结果填充进第五步的结果中。

(7) 用H作用于第六步生成的数据流,输出最终结果

7.总结

SSL客户端(也是TCP的客户端)在TCP链接建立之后,发出一个ClientHello来发起握手,这个消息里面包含了自己可实现的算法列表和其它一些需要的消息,SSL的服务器端会回应一个ServerHello,这里面确定了这次通信所需要的算法,然后发过去自己的证书(里面包含了身份和自己的公钥)。Client在收到这个消息后会生成一个秘密消息,用SSL服务器的公钥加密后传过去,SSL服务器端用自己的私钥解密后,会话密钥协商成功,双方可以用同一份会话密钥来通信了。

作者:AstrophelYang