HTTPS
HTTPS(HyperText Transfer Protocol Secure)中文译作超文本传输安全协议,这是一种通过计算机网络进行安全通讯的传输协议。
HTTPS 本质上还是由 HTTP 进行通信,只是在 HTTP 协议和 TCP 层之间增加了一个 SSL 的安全传输协议。整个传输的加密过程都在新的安全层 SSL/TLS 中实现,而原来的 HTTP 层的传输流程保持不变,这样就很好地兼容了旧的 HTTP 协议,也沿袭了 TCP/IP 协议族的分层思想。
通过 HTTPS,客户端可以确认服务端的身份,保证数据在传输过程中不被篡改,当我们在自己的浏览器上与某一个网站建立 HTTPS 连接的时候,满足如下情况可以表示这个服务端可以被信任:
- 首先我们的操作系统中安装了正确且受信任的证书。我们在 cmd 命令行中执行
certmgr.msc
命令,可以查看操作系统已经安装的证书列表。
- 浏览器本身正确实现了 HTTPS。
- 被访问的网站提供了一个证书,这个证书是由一个操作系统所信任的证书颁发机构签发的,操作系统所信任的证书颁发机构一般都预装在操作系统中,通过第一步的方式可以查看。
- 被访问的网站所提供的证书被成功认证。
3. TLS/SSL
前面我们提到,HTTPS 就是在 HTTP 的基础之上增加了 TLS/SSL,那么这两个东西该如何理解呢?
SSL/TLS 是一种密码通信方案,算是目前使用最广泛的密码通信方案了。SSL 全称是 Secure Socket Layer,中文译作安全套接层,是 1994 年由 Netscape 公司设计的一套协议,并与 1995 年发布了 3.0 版本;TLS 全称是 Transport Layer Security,中文译作传输层安全,则是 IETF 在 SSL3.0 基础上设计的协议,实际上相当于 SSL 的后续版本,目前 TLS 先后迭代了 TLS 1.0
、TLS 1.1
、TLS 1.2
和 TLS 1.3
,目前被广泛使用的是 TLS 1.2
版本。
SSL/TLS 涉及到了密码学中的对称加密、非对称加密、数字签名等等,算是密码学领域里的集大成者了。
TLS
接下来我们就来看看 TLS 如何确保 HTTP 安全。
为了确保客户端和服务端之间的数据安全,我们很容易想到一种方案就是对传输的数据进行加密,没错,这是一个办法,事实上也是这么做的。
加密又分为两种:
- 对称加密
- 非对称加密
那么该使用哪一种呢?
对称加密,也就是加密密钥和解密密钥是同一个,当浏览器和服务端需要进行通信的时候,约定好一个密钥,然后使用这个密钥对发送的消息进行加密,对方收到消息之后再使用相同的密钥对消息进行解密。但是,在 B/S 架构的项目中,这种方案显然不合适,一个网站把自己的密钥告诉全世界所有的浏览器,那加密和不加密还有区别吗?
有小伙伴可能又想到了不对称加密,不对称加密倒是个办法,因为不对称加密是有一个密钥对公钥和私钥,公钥可以公布出来告诉所有人,私钥只有自己知道。通信的时候,客户端首先使用公钥对消息进行加密,服务端收到之后,再通过私钥对消息进行解密,这看起来似乎挺完美的。但是!!!非对称加密存在一个问题,就是非对称加密和解密相当耗时,通过这种方式处理加解密效率太低。
那怎么办?我们可以将两者结合起来。
具体来说,就是这样:首先服务端会生成一个非对称加密的密钥对,私钥自己保存,公钥发送给客户端,客户端拿到这个公钥之后,再生成一个对称加密的密钥,然后把对称加密的密钥通过公钥进行加密,加密之后发送给服务端,服务端通过私钥进行解密,这样客户端和服务端就可以通过对称加密进行通信了。
事实上,TLS 大致上的思路就是这样的。
不过上面这个方案还是有一个漏洞,那就是服务端要通过明文传输的方式把公钥发送给客户端,这个过程还是不安全的,可能被人恶意截胡,那么这个问题该如何解决呢?
这就涉及到另外一个概念叫做数字证书了。
CA
数字证书是一个包含了目标网站各种信息如网站域名、证书有效期、签发机构、用于生成对称密钥的公钥、上级证书签发的签名等的文件,通过数字证书我们可以确认一个用户或者服务站点的身份。
实际场景中的数字证书是一系列的,形成了一个信任链,信任链的最顶端是 CA。
CA 是 Certificate Authority 的简写,它是一个负责发放和管理数字的证书的第三方权威机构。CA 的工作流程是这样的:
- CA 自己给自己颁发的用自己的私钥签名的证书称为根证书,根证书的私钥安全性至关重要,根证书的私钥都是被保存在离线计算机中,有严格的操作规章,每次需要使用时,会有专人将数据通过 USB 拷贝过去,操作完了以后,再将数据带出来(这个专指 CA 根证书的私钥)。
- 一个用户想要获取一个证书,首先自己得有一个密钥对,私钥自己留着,公钥以及其他信息发送给 CA,向 CA 提出申请,CA 判明用户的身份之后,会将这个公钥和用户的身份信息绑定,并且为绑定后的信息进行签名(签名是通过 CA 根证书的私钥进行的),最后将签名后的证书发给申请者。
- 一个用户想要鉴定一个证书的真伪,就通过 CA 的公钥对证书上的数字签名进行验证,验证通过,就认为这个这个证书是有效的。
上面这个流程中有一个重要前提,那就是 CA 受到大家所有人的信任。
然而在实际操作中,我们并不能直接去跟 CA 申请一个数字证书,因为全世界要认证的内容太多了,CA 搞不过来,而且频繁的找 CA 申请,还有可能导致私钥泄漏,这可就是一个大的灾难了。
那怎么办呢?实际操作中,我们可以基于 CA 来构建一个信任链。具体来说,步骤是这样:
- 首先我们的手机、笔记本等操作系统中都预装了 CA 颁发的根证书,他们是所有信任构建的基石。
- 假设 CA 签发了一个证书 A,在这个过程中 CA 称为 Issuer,A 称为 Subject,假设 A 是一个受信任的中间证书,已经预装在我们的操作系统中了。现在由 A 利用它自己的私钥给某一个网站签发了一个证书 B。
- 现在当我们的电脑需要访问该网站的时候,该网站就会给我们发来一个证书 B,由于我们的浏览器并不知道 B 证书是否合法,但是我们的电脑上已经预装了 A 证书,我们可以从 A 证书中提取出 A 的公钥,然后利用 A 的公钥对 B 证书的签名进行验证(因为 B 证书的签名是 A 的私钥签的),如果验证通过了,就说明 B 是合法的。
- 相同的道理,B 也可以继续签发 C 证书,C 继续签发 D 证书,这样就形成了一个信任链。
- 如果服务端的签名是 D 证书,那么一般来说,服务器返回给浏览器的就会包含 B、C、D 三个证书(因为 A 证书已经在我们的电脑上了),即使只返回 D 证书,浏览器也可以根据 D 书中的信息,自动下载到 B、C 两个证书然后进行验证。
总结一下:
- CA 是一个权威的机构,是一个发证机关,CA 发出来的证书可以证明一个人或者组织的身份。
- 任何人都可以得到 CA 的证书(含公钥),用以验证 CA 所签发的证书。
- 每一个数字证书都是由上级证书的私钥来签发的,处于最顶层的就是 CA 签发的根证书了,这个根证书没有上级证书了,所以这个根证书实际上是由 CA 自己的私钥来签发的,这也叫做自签名,即 Self-Signed。
当我们有了数字签名之后,就可以解决 3.1 小节最后提出的问题了。服务端将数字签名发给浏览器,浏览器利用系统已经内置的公钥验签,确认签名没问题,然后就提取出来数字签名中的公钥,开始协商对称加密的私钥了
SSL证书通过提供网站和服务器之间的安全握手和密钥交换过程来确保通信的安全性。
首先,网站所有者需要向受信任的证书颁发机构(CA)申请SSL证书。证书颁发机构会对网站所有者的身份进行验证,并为其生成一个数字证书。当用户访问使用SSL证书保护的网站时,网站会将其证书发送给用户的浏览器。浏览器会验证证书的有效性,包括检查证书的签名是否有效、证书是否过期以及证书是否与网站的域名匹配。如果证书有效,浏览器会生成一个随机的对称密钥,并使用网站的公钥对该密钥进行加密。
然后,浏览器将加密后的密钥发送回服务器。服务器收到加密后的密钥后,使用自己的私钥进行解密,得到对称密钥。此时,网站和浏览器都拥有相同的对称密钥,用于加密和解密后续的通信。接下来,网站和浏览器使用对称密钥进行加密和解密数据。
这样,即使有人截获了通信数据,也无法解密其中的内容,因为只有网站和浏览器才知道对称密钥。通过SSL证书的安全握手和密钥交换过程,网站和服务器之间的通信得到了保护,确保数据的机密性和完整性。同时,SSL证书还可以防止中间人攻击,确保用户与网站之间的通信是安全的。
TLS
TLS协议就是实现了这一过程安全协议。TLS是在TCP之上,应用层之下实现的网络安全方案。在TCP/IP四层网络模型中属于应用层协议。TLS协议在两个通信应用程序之间提供数据保密性和数据完整性,另外还提供了连接身份可靠性方案。
UDP则使用DTLS协议实现安全传输,和TLS协议类似。
什么是证书链
在进一步讨论之前,我们需要先引入证书链的概念。简单来说,证书链是指您的SSL证书以及它如何链接回受信任的证书颁发机构。证书链分为三个部分:根证书、中间证书、服务器证书。当你访问一个网站时,浏览器会查看它的SSL证书,并快速的验证证书的真实性。浏览器正是循着证书链对证书进行身份验证的操作,因此证书链也称为证书路径或信任链。
什么是根证书
根证书,通常称为可信根,是属于证书颁发机构(CA)的数字证书。当一个CA被建立时,它不是预先信任的。在给定时间内,该CA通过由已受信任的CA颁发的交叉签名中间证书开展业务。交叉证书是由一个CA颁发的数字证书,用于为另一个CA的根证书签署公钥。一旦CA的应用程序被接受并证明自己值得信赖,它就会将其根添加到根存储中。根存储是预先下载的根证书及其公钥的集合,这些证书驻留在设备上。
根证书是无价的,因为任何使用其私钥签名的证书都会自动受到浏览器的信任。由于这些根证书的价值,以及其中一个被破坏所带来的风险,它们很少用于颁发最终实体证书。相反,我们使用中间证书。
什么是中间证书
中间证书像树枝一样从根证书分支出来。他们充当受保护的根证书和向公众颁发的服务器证书之间的中间人。其工作原理如下:根CA使用它的私钥对中间根签名,使它受到信任。然后根CA使用中间证书的私钥签署和颁发终端用户SSL证书。这个过程可以重复几次,其中一个中间根签署另一个中间根,最后签署一个终端实体证书。这些从根到中间到终端实体的链接也就是证书链。
根证书与中间证书的区别
我们可以通过查看证书本身来区分根证书和中间证书。如果Issuedto和Issuedby字段相同则它是根证书,否则它是中间证书。另一个识别是查看认证路径,出现在列表顶部的证书是根证书。
以上就是根证书与中间证书的基本描述和区别所在,本质上这些都归结到一个词:PKI或公钥基础设施。但除非你对此有深入了解,否则它看起来十分抽象。
作为国内数字安全证书行业领先者,锐成信息****(racent.com)自于2011年起,就一直深耕于以SSL证书为主的数字证书领域,提供自有国产品牌锐安信sslTrus及全球多个知名品牌的SSL证书,可为您的网站加密数据传输,切实防护企业信息安全。如您有更多疑问或需求,可搜索锐成信息获得支持。
发展历史
TLS协议的前身SSL协议是网景公司设计的主要用于Web的安全传输协议,这种协议在Web上获得了广泛的应用。
1994年,网景公司设计了SSL协议的1.0版,因为存在严重的安全漏洞,未公开。
2.0版本在1995年2月发布,但因为存在数个严重的安全漏洞(比如使用MD5摘要、握手消息没有保护等),2011年RFC 6176 标准弃用了SSL 2.0。
3.0版本在1996年发布,是由网景工程师完全重新设计的,同时写入RFC,较新版本的SSL/TLS基于SSL 3.0。2015年,RFC 7568 标准弃用了SSL 3.0。
1999年,IETF将SSL标准化,并将其称为TLS(Transport Layer Security)。从技术上讲,TLS 1.0与SSL 3.0的差异非常微小。
-
TLS 1.1在RFC 4346中定义,于2006年4月发表,主要修复了CBC模式的BEAST攻击等漏洞。
微软、Google、苹果、Mozilla四家浏览器业者将在2020年终止支持TLS 1.0及1.1版。
TLS 1.2在RFC 5246中定义,于2008年8月发表,添加了增加AEAD加密算法,如支持GCM模式的AES。
TLS 1.3在RFC 8446中定义,于2018年8月发表,砍掉了AEAD之外的加密方式。
协议设计目标
- 加密安全:TLS应用于双方之间建立安全连接,通过加密,签名,数据摘要保障信息安全。
- 互操作性:程序员在不清楚TLS协议的情况下,只要对端代码符合RFC标准的情况下都可以实现互操作。
- 可扩展性:在必要时可以通过扩展机制添加新的公钥和机密方法,避免创建新协议。
- 相对效率:加密需要占用大量CPU,尤其是公钥操作。TLS协议握手完成后,通过对称密钥加密数据。TLS还集成了会话缓存方案,减少需要从头建立连接的情况。
记录协议
TLS协议是一个分层协议,第一层为TLS记录层协议(Record Layer Protocol),该协议用于封装各种高级协议。目前封装了4种协议:握手协议(Handshake Protocol)、改变密码标准协议(Change Cipher Spec Protocol)、应用程序数据协议(Application Data Protocol)和警报协议(Alert Protocol)。
Change Cipher Spec Protocol
在TLS1.3被去除。
记录层包含协议类型、版本号、长度、以及封装的高层协议内容。记录层头部为固定5字节大小。
在TLS协议规定了,如接收到了未定义的协议协议类型,需要发送一个
unexpected_message
警报。
握手步骤
- 当客户端连接到支持TLS协议的服务端要求创建安全连接并列出了受支持的算法套件(包括加密算法、散列算法等),握手开始。
- 服务端从客户端的算法套件列表中指定自己支持的一个算法套件,并通知客户端,若没有则使用一个默认的算法套件。
- 服务端发回其数字证书,此证书通常包含服务端的名称、受信任的证书颁发机构(CA)和服务端的公钥。
- 客户端确认其颁发的证书的有效性。
- 为了生成会话密钥用于安全连接,客户端使用服务端的公钥加密随机生成的密钥,并将其发送到服务端,只有服务端才能使用自己的私钥解密。
- 利用随机数,双方生成用于加密和解密的对称密钥。这就是TLS协议的握手,握手完毕后的连接是安全的,直到连接(被)关闭。如果上述任何一个步骤失败,TLS握手过程就会失败,并且断开所有的连接。
握手协议
TLS 握手协议允许服务端和客户端相互进行身份验证,并在应用程序协议传输或接收其第一个字节数据之前协商协议版本、会话ID、压缩方法、密钥套件、以及加密密钥。
完整的TLS握手流程,流程如下
- 表示可选步骤或与实际握手情况相关。比如重建已有连接,服务端无需执行Certificate,再比如使用RSA公钥加密时,无需ServerKeyExchange。
握手协议消息必须按上面流程的发送数据进行发送,否则需要以致命错误告知对方并关闭连接。
完整的握手流程有时候也被称为2-RTT流程,即完整的握手流程需要客户端和服务端交互2次才能完成握手。
交互应用请求到响应的交互时间被称为往返时间(Round-trip Time)
握手协议的结构如下,其中协议头的ContentType固定为22
,接下来是TLS版本号,TLS1.2为0303
,最后是用2字节表示长度。
握手协议类型包含以下:
- hello_request:0
- client_hello:1
- server_hello:2
- certificate:3
- server_key_exchange :12
- certificate_request:13
- server_hello_done:14
- certificate_verify:15
- client_key_exchange:16
- finished:20
Hello Message是具体的握手协议类型内容,不同协议内容有所不同。
Hello Request
Hello Request
消息用于客户端与服务端重新协商握手,该消息可能由服务端在任何时刻发送。Hello Request
消息非常简单,没有其他冗余信息。
当客户端收到了服务端的Hello Request
时可以有以下4种行为:
- 当客户端正在协商会话,可以忽略该消息。
- 若客户端未在协商会话但不希望重新协商时,可以忽略该消息。
- 若客户端未在协商会话但不希望重新协商时,可以发送
no_renegotiation
警报。 - 若客户端希望重新协商会话,则需要发送
ClientHello
重新进行TLS握手。
服务端发送完HelloRequest
消息,可以有以下几种行为:
- 服务端发送了
HelloRequest
消息,但未收到ClientHello
时,可以通过致命连接警报关闭连接。 - 服务端发送了
HelloRequest
消息,必须等待握手协商处理完成后才可以继续处理应用数据消息。
Finished和Certificate的握手消息验证不包括该消息的hash。
Client Hello
当客户端首次与服务端建立连接或需要重新协商加密握手会话时,需要将Client Hello
作为第一条消息发送给服务端。
Client Hello
消息包含了许多重要信息,包括客户端版本号、客户端随机数、会话ID、密钥套件、压缩方式、扩展字段等。
客户端版本号:客户端支持的最新TLS版本号,服务端会根据该协议号进行协议协商。
-
32位随机数:客户端生成的32位随机数。前4位是Unix时间戳,该时间戳为1970年1月1日0点以来的秒数。不过TLS并没有强制要求校验该时间戳,因此允许定义为其他值。后面28位为一个随机数。
通过前4字节填写时间方式,有效的避免了周期性的出现一样的随机数。使得"随机"更加"随机"。
在TLS握手时,客户端和服务端需要协商数据传输时的加密密钥。为了保证加密密钥的安全性。密钥需要通过客户端和服务端一起生成。客户端和服务端都提供一个32位的随机数,通过该随机数使用基于HMAC的PRF算法生成客户端和服务端的密钥。 -
会话ID:用于表示客户端和服务端之间的会话。实际的会话ID是由服务端定义的,因此即使是新的连接,服务端返回的会话ID可能也会和客户端不一致,由于会话ID是明文传输的,因此不能存放机密信息。
- 若会话ID是新的,则客户端和服务端需要建立完整的TLS握手连接流程。
- 若会话ID是较早连接的会话ID,则服务端可以选择无需执行完整的握手协议。
算法套件:客户端将支持的加密算法组合排列后发送给服务端,从而和服务端协商加密算法。服务端根据支持算法在ServerHello返回一个最合适的算法组合。
算法套件的格式为TLS_密钥交换算法身份认证算法WITH对称加密算法消息摘要算法,比如TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
,密钥交换算法是DHE
,身份认证算法是RSA
,对称加密算法是AES_256_CBC,消息摘要算法是SHA256,由于RSA又可以用于加密也可以用于身份认证,因此密钥交换算法使用RSA时,只写一个RSA,比如TLS_RSA_WITH_AES_256_CBC_SHA256
压缩方式:用于和服务端协商数据传输的压缩方式。由于TLS压缩存在安全漏洞,因此在TLS1.3中已经将TLS压缩功能去除,TLS1.2算法也建议不启用压缩功能。
扩展字段:可以在不改变底层协议的情况下,添加附加功能。客户端使用扩展请求其他功能,服务端若不提供这些功能,客户端可能会中止握手。对于扩展字段的详细定义可以看Transport Layer Security (TLS) Extensions
客户端发送完
ClientHello
消息后,将等待ServerHello
消息。 服务端返回的任何握手消息(HelloRequest
除外)将被视为致命错误。
Server Hello
当服务端接收到ClientHello
,则开始TLS握手流程, 服务端需要根据客户端提供的加密套件,协商一个合适的算法簇,其中包括对称加密算法、身份验证算法、非对称加密算法以及消息摘要算法。若服务端不能找到一个合适的算法簇匹配项,则会响应握手失败的预警消息。
-
版本号:服务端根据客户端发送的版本号返回一个服务端支持的最高版本号。若客户端不支持服务端选择的版本号,则客户端必须发送
protocol_version
警报消息并关闭连接。若服务端接收到的版本号小于当前支持的最高版本,且服务端希望与旧客户端协商,则返回不大于客户端版本的服务端最高版本。
若服务端仅支持大于client_version的版本,则必须发送protocol_version
警报消息并关闭连接。
若服务端收到的版本号大于服务端支持的最高版本的版本,则必须返回服务端所支持的最高版本。 32位随机数:服务端生成的32位随机数,生成方式和客户端一样。服务端生成随机数的可以有效的防范中间人攻击,主要是通过防止重新握手后的重放攻击。
-
会话ID:用于表示客户端和服务端之间的会话。若客户端提供了会话ID,则可以校验是否与历史会话匹配。
若不匹配,则服务端可以选择直接使用客户端的会话ID或根据自定义规则生成一个新的会话ID,客户端需要保存服务端返回的会话ID当作本次会话的ID。
-
若匹配,则可以直接执行1-RTT握手流程,返回ServerHello后直接返回
ChangeCipherSpec
和Finished
消息。
在Finished消息中和完整握手一样都需要校验VerifyData。
-
算法套件:服务端根据客户端提供的算法套件列表和自己当前支持算法进行匹配,选择一个最合适的算法组合,若没有匹配项,则使用默认的
TLS_RSA_WITH_AES_128_CBC_SHA
。TLS1.2协议要求客户端和服务端都必须实现密码套件
TLS_RSA_WITH_AES_128_CBC_SHA
压缩方式:用于和服务端协商数据传输的压缩方式。由于TLS压缩存在安全漏洞,因此在TLS1.3中已经将TLS压缩功能去除,TLS1.2算法也建议不启用压缩功能。
扩展字段:服务端需要支持接收具有扩展和没有扩展的ClientHello。服务端响应的扩展类型必须是
ClientHello
出现过才行,否则客户端必须响应unsupported_extension
严重警告并中断握手。
RFC 7568要求客户端和服务端握手时不能发送
{3,0}
版本,任何收到带有协议Hello消息的一方版本设置为{3,0}
必须响应protocol_version
警报消息并关闭连接。
通过ClientHello
和ServerHello
,客户端和服务端就协商好算法套件和用于生成密钥的随机数。
Certificate
假设客户端和服务端使用默认的TLS_RSA_WITH_AES_128_CBC_SHA
算法,在ServerHello
完成后,服务端必须将本地的RSA证书传给客户端,以便客户端和服务端之间可以进行非对称加密保证对称加密密钥的安全性。
RSA的证书有2个作用:
- 客户端可以对服务端的证书进行合法性进行校验。
- 对
Client Key Exchange
生成的pre-master key进行公钥加密,保证只有服务端可以解密,确保对称加密密钥的安全性。
发送给客户端的是一系列证书,服务端的证书必须排列在第一位,排在后面的证书可以认证前面的证书。
当客户端收到了服务端的ServerHello
时,若客户端也有证书需要服务端验证,则通过该握手请求将客户端的证书发送给服务端,若客户端没有证书,则无需发送证书请求到服务端。
证书必须为X.509v3格式。
Server Key Exchange
使用RSA公钥加密,必须要保证服务端私钥的安全。若私钥泄漏,则使用公钥加密的对称密钥就不再安全。同时RSA是基于大数因式分解。密钥位数必须足够大才能避免密钥被暴力破解。
1999年,RSA-155 (512 bits) 被成功分解。
2009年12月12日,RSA-768 (768 bits)也被成功分解。
在2013年的棱镜门事件中,某个CA机构迫于美国政府压力向其提交了CA的私钥,这就是十分危险的。
相比之下,使用DH算法通过双方在不共享密钥的情况下双方就可以协商出共享密钥,避免了密钥的直接传输。DH算法是基于离散对数,计算相对较慢。而基于椭圆曲线密码(ECC)的DH算法计算速度更快,而且用更小的Key就能达到RSA加密的安全级别。ECC密钥长度为224~225位几乎和RSA2048位具有相同的强度。
ECDH:基于ECC的DH算法。
另外在DH算法下引入动态随机数,可以避免密钥直接传输。同时即使密钥泄漏,也无法解密其他消息,因为双方生成的动态随机数无法得知。
在密码学中该特性被称为前向保密
DHE: 通过引入动态随机数,具有前向保密的DH算法。
ECDHE:通过引入动态随机数,具有前保密的ECDH算法。
Certificate Request
当需要TLS双向认证的时候,若服务端需要验证客户端的证书,则向客户端发送Certificate Request
请求获取客户端指定类型的证书。
- 服务端会指定客户端的证书类型。
- 客户端会确定是否有合适的证书。
Server Hello Done
当服务端处理Hello请求结束时,发送Server Hello Done
消息,然后等待接收客户端握手消息。客户端收到服务端该消息,有必要时需要对服务端的证书进行有效性校验。
Client Certificate
当客户端收到了服务端的CertificateRequest
请求时,需要发送Client Certificate
消息,若客户端无法提供证书,则仍要发送此消息,消息内容可以不包含证书。
Client Key Exchange
客户端接收到ServerHelloDone消息后,计算密钥,通过发送Client Key Exchange
消息给服务端。客户端和服务端通过Key Exchange
消息交换密钥,使得双方的主密钥协商达成一致。
以RSA的密钥协商为例。在ClientHello
和ServerHello
分别在客户端和服务端创建了一个32位的随机数。客户端接收到Server Hello Done
消息时,生成最后一个48位的预主密钥。通过服务端提供的证书进行公钥加密,以保证只有服务端的私钥才能解密。
其中预主密钥的前2位要求使用
Client Hello
传输的TLS版本号(存在一些TLS客户端传递的时协商后的TLS版本号,对该版本号检查时可能会造成握手失败)。
需要注意的是,若RSA证书的填空格式不正确,则可能会存在一个漏洞导致客户端发送的PreMasterSecret被中间人解密造成数据加密的对账密钥泄漏。可以看下Attacking RSA-based Sessions in SSL/TLS
Certificate Verify
若服务端要求客户端发送证书,且客户端发送了非0长度的证书,此时客户端想要证明自己拥有该证书,则需要使用客户端私钥签名一段数据发送给服务端继续验证。该数据为客户端收发的所有握手数据的hash值(不包括本次消息)。
Finished
当发送完Change Cipher Spec
消息后必须立即发送该消息。当该消息用于验证密钥交换和身份验证过程是否成功。
Finished
消息是第一个使用协商的算法簇进行加密和防篡改保护的消息。一旦双方都通过了该消息验证,就完成了TLS握手。
VerifyData为客户端收发的所有握手数据的hash值(不包括本次消息)。与Certificate Verify
的hash值可能会不一样。如果发送过Certificate Verify
消息,服务端的握手消息会包含Certificate Verify
握手的数据。
需要注意的是,握手数据不包括协议头的握手协议明文数据(服务端返回
Finished
的验证握手数据是包含接收到客户端的Finished
的明文hash值)。
Finished
消息数据加密和Appilication Data
一致,具体数据加密在Application Data
段进行说明。
改变密码标准协议
改变密码标准协议是为了在密码策略中发出信号转换信号。 该协议由一条消息组成,该消息在当前(不是挂起的)连接状态下进行加密和压缩。 消息由值 1 的单个字节组成。
在接收到该协议后,所有接收到的数据都需要解密。
警报协议
警报消息传达消息的严重性(警告或致命)和警报的说明。具有致命级别的警报消息会导致立即终止连接。
若在改变密码标准协议前接收到警报消息,是明文传输的,无需解密。
与其他消息一样,警报消息按当前连接状态指定进行加密和压缩。在接收到改变密码标准协议后接收到警报协议,则需要进行解密。解密后即为警报协议明文格式。
加密的Alert消息和加密数据一样,都需要递增加密序号,在数据解密时,递增解密序号。
应用程序数据协议
当客户端和服务端Finished
发送完毕并验证通过后,握手就结束了。后续所有数据都会使用握手协商的对称密钥进行数据加密。
TLS协议实现了数据加密和MAC计算。一般来说有3种加密模式,分别为:
- Mac-then-Encrypt:在明文上计算MAC,将其附加到数据,然后加密明和+MAC的完整数据。
- 加密和MAC:在明文上计算MAC,加密明文,然后将MAC附加到密文的末尾
- Encrypt-then-Mac:加密明文,然后在密文上计算MAC,并将其附加到密文。
TLS协议使用的是Mac-then-Encrypt
。首先将加密的序号、ContentType、数据长度、数据进计算HMAC-SHA256摘要。然后将摘要拼接到数据后,通过PKCS7格式对摘要+MAC数据进行填充对其和加密块大小一致。最后摘要+MAC+对其填充块
进行加密。
需要注意的是应用程序数据消息有最大长度限制2^14 + 2048
,当超过长度后,数据需要分段传输。每一段都当作单独的数据段进行单独MAC地址并加密。
结语
TLS1.2版本是目前最常用的TLS协议,TLS1.3版本于2018年发表,目前并没有广泛使用。
使用TLS1.2需要注意以下几点:
- 若使用RSA非对称加密,则需要尽可能使用2048位长度的密钥。
- 尽可能可以使用具有前向安全性的加密算法,如ECDHE算法进行非对称加密。
- 使用AEAD认证加密(GCM)代替CBC块加密。