当前位置: 首页 > news >正文

TLS协议详解

TLS协议

一,TLS协议的组成

image

TLS协议架构模块分为两层:TLS记录协议,TLS握手协议

TLS记录协议: 是所有子协议的基层,规定了TLS收发数据的基本单位。所有子协议都需要通过记录协议发出,多个记录数据可以在一个TCP中发送。主要负责使用对称密码对消息进行加密。

TLS握手协议:

  • 握手协议:客户端和服务端在握手过程中协商 TLS版本号,随机数,密码套件,交换证书,最终获取会话密钥。
  • 密码规格变更协议:发送一个通知,告知对方后续的通信采用加密保护。
  • 警告协议:向对方发出警告,类似于http中的状态码。不支持旧版本,证书异常都会发送警报,另一方收到警报后可以进行相应的处理
  • 应用数据协议:将TLS承载的应用数据传达给通信对象

二,TLS的握手过程

image

上图是TLS握手的一个简易流程,每一个框就是一个 TLS Record(记录),多个Record合并成一个TCP来进行发送,可以看到整个TLS握手只需要2次消息往返即2RTT就能完成 ( TLS 1.2是2RTT,TLS 1.3可以做到 1RTT甚至0RTT )

接下来我们来结合wireshark抓包来详细介绍每一步的流程:

1,ClientHello

image
首先客户端先向服务端发起握手请求,在这个请求过程中client会携带以下参数

  • TLS 版本: 确定使用1.2还是1.3 但是这个地方固定是1.2。之后我们会在1.2与1.3的兼容性中聊到
  • Client提供的随机数: 用于后续生成会话密钥
  • Cipher Suites: 可用密码套件列表,供服务端选择
  • 会话ID(可忽略): 可用于之后TLS1.3的优化 —— 会话缓存
  • 可用压缩方式
密码套件

客户端和服务端在使用TLS建立连接时需要选择一组恰当的加密算法来实现安全通信,这些算法的组合就被称为 密码套件
如图中的密码套件那一行:TLS_ECDHE_RSA_WITH_AES_128-CBC-SHA 他的意思是

  • 握手时使用ECDHE算法进行密钥交换
  • 用RSA签名和身份认证
  • 握手后的通信使用 AES对称算法,密钥长度 128 位
  • 分组模式为 CBC
  • 摘要算法为 SHA 用于消息认证和产生随机数

2,ServerHello

服务端接收到客户端的握手请求,会回复客户端同时 发送 ServerHello,ServerHello会根据之前的ClientHello的参数来做如下操作:

  • **确认 TLS版本 **
  • 服务器提供的随机数
  • 选择的密码套件

3,Server Certificate

数字证书 与 CA

① CA证书:
我们知道 在 https中 加密采用了非对称加密,通过私钥加密,公钥解密。私钥由双方生成并维护。但是公钥不能任意生成,公钥涉及到一个公钥信任问题,谁都能发布公钥的话,黑客就可以伪造公钥来进行攻击。所以说公钥得由一个公认可信的第三方生成,让他作为信任的起点,递归的终点,构建信任链,这个第三方就是 CA(证书认证机构)

② CA证书链:
CA可以签发三种证书,他们的区别在于可信程度,按照可信程度从高到低来排序即为:EV, OV, DV
CA如果想证明自己,可以找上级CA为自己签发证书,不断向上直到 Root CA。Root CA会给自己签发自签名证书或者根证书,这个证书是必须相信的。

如下图所示即为数字证书CA的信任链
image

③ 证书弱点:
证书的签发可能失误或者被欺骗,签发了错误的证书,这个时候可以通过 CRL(证书吊销列表) 和 OCSP(在线证书状态协议)来及时对问题证书进行废止

服务端会将自己的证书链发送给客户端,交给客户端进行验证。值得注意的不是只发送一个证书,前文有说到 二级CA的证明需要一级CA的证明,验证二级证书的签名需要一级证书的公钥来进行解密,所以需要返回一整个证书链(无需携带根证书,用户浏览器自带了根证书)

4,Server Key Exchange

以 ECDHE算法为例,服务端生成一个 公钥 名为Server Params,用来实现密钥交换算法,再用私钥进行签名认证

Handshake Protocol: Server Key Exchange
    EC Diffie-Hellman Server Params
        Curve Type: named_curve (0x03)
        Named Curve: x25519 (0x001d)
        Pubkey: 3b39deaf00217894e...
        Signature Algorithm: rsa_pkcs1_sha512 (0x0601)
        Signature: 37141adac38ea4...
 

5,Client Key Exchange

客户端首先会先对证书链进行验证,再根据服务端所选的算法以及Server Params来生成对应的Client Params返回给服务端

Handshake Protocol: Client Key Exchange
    EC Diffie-Hellman Client Params
        Pubkey: 8c674d0e08dc27b5eaa…

此时服务端和客户端拥有了 Client Params,Server Params,Client Random,Server Random,服务端会先使用Params用ECDHE算法生成一个Pre-Master,再用 Random + Pre-Master 生成主密钥 Master Secret。

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

// 之所以需要使用三个随机数来生成主密钥,是因为TLS的设计者并不信任服务端和客户端生成的随机数的可靠性。所以将三个不可靠的随机数混合起来来提升随机数的随机程度。

有了主密钥后并不会直接进行使用,而是通过PRF算法扩展出更多的派送会话密钥,来用作每次会话的独立密钥。这样即使主密钥泄露已传输的数据仍然安全,因为每次会话的密钥是独立的具备前向安全性。

6,Change Chiper Spec & Finished

通信转换为使用会话密钥 + 对称算法进行加密通信,并且握手结束。
由于使用的是ECDHE,客户端可以无需等待服务端返回 Finished就直接发出HTTP报文,省去等待一个消息返回的时间浪费,这个叫做
TLS False Start

图示总结(以ECDHE握手为例)

三,TLS 1.3

TLS 1.3 相比于 TLS 1.2有了以下几项巨大的提示:兼容,性能,安全

1,兼容性

在TLS 1.2时期,版本号是记录在Version字段的,即Version:TLS 1.2(0x0303)。我们可能理所应当的认为TLS 1.3就是Version:TLS 1.3(0X0304)。但是这样肯定不行,这样会导致大量只认老协议的代理服务器,网关都无法处理请求,导致握手失败。

如果要进行区分1.2 和 1.3就要通过新引入的协议 扩展协议,在当前的记录后添加一列拓展字段,老版本因为不认识则直接舍弃,新版本则可以对其进行识别处理,这便实现了向后兼容

所以 TLS 1.3 还是保留 Version:TLS 1.2(0x0303),只不过在 扩展协议 中新加了有一个 #supported_version扩展,在这个扩展中标记了TLS的版本号

Handshake Protocol: Client Hello
    Version: TLS 1.2 (0x0303)
    Extension: supported_versions (len=11)
        Supported Version: TLS 1.3 (0x0304)
        Supported Version: TLS 1.2 (0x0303)

2,性能提升

TLS 1.3 相比于 TLS 1.2最大性能提升就是 原先TLS1.2握手需要 2RTT,现在TLS1.3握手只需 1RTT,性能整整提升了一倍。
image
优化的点如下:
1,TLS 1.3舍弃了之前的繁琐的协商方式,在第一次Client Hello时 通过扩展组就将签名算法,客户端公钥参数(Client Params)等等内容全部提供了服务端。同时服务端会在Server Hello时就携带好各种参数以及ChangeCipherSpec。

通过这两点 成功将握手的报文发送提升至 1RTT

3,安全性(待补充)

废弃了一些分组和加密算法,由于没具体学加密算法,学了之后再补充

密码套件大大减少,得益于密码套件的减少,在Client Hello阶段可以直接生成公钥参数以及曲线
image

四, TLS 1.3 握手过程

1,Client Hello

Handshake Protocol: Client Hello
    Version: TLS 1.2 (0x0303)
    Random: cebeb6c05403654d66c2329…
    Cipher Suites (18 suites)
        Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301)
        Cipher Suite: TLS_CHACHA20_POLY1305_SHA256 (0x1303)
        Cipher Suite: TLS_AES_256_GCM_SHA384 (0x1302)
    Extension: supported_versions (len=9)
        Supported Version: TLS 1.3 (0x0304)
        Supported Version: TLS 1.2 (0x0303)
    Extension: supported_groups (len=14)
        Supported Groups (6 groups)
            Supported Group: x25519 (0x001d)
            Supported Group: secp256r1 (0x0017)
    Extension: key_share (len=107)
        Key Share extension
            Client Key Share Length: 105
            Key Share Entry: Group: x25519
            Key Share Entry: Group: secp256r1

TLS 1.3与TLS 1.2相比而言,新增了三个拓展项

  • supported_version:这个我们之前有提到,TLS 1.3需要使用该拓展项来进行版本区分
  • supported_group:支持的曲线
  • key_share:曲线对应的参数

可以看到相比于1.2,1.3再hello的时候就将自身支持的参数发送给了服务端

2,Server Hello

收到客户端的消息后,此时服务端就拥有了 Client Random 和 Server Random 、Client Params 和 Server Params,可以直接通过ECDHE算出 Pre-Master。

此时通过 Certificate Verify一个安全增强措施,用私钥将曲线,套件,参数等数据进行数字签名,强化了身份认证和防篡改。

可以发现 生成会话密钥以及进入加密通信的时间要比TLS 1.2更加的早。TLS 1.2还需要进行一次繁琐的 Key Exchange,而1.3在两次Hello中就已经完成了Key的交换

五,HTTPS的优化

HTTPS在HTTP握手的基础上加上了一个TLS握手,所以他的连接速度肯定也会有所下降,有时甚至会比HTTP慢上几秒(远古时期),这下子 HTTPS的已经刻板印象的变成 “Slow” 了。那本章我们来分析 HTTPS究竟慢在哪以及如何优化。

首先HTTPS的加密分为了两部分 TLS握手前的非对称加密TLS握手后的对称加密
**对称加密:**目前TLS支持的对称加密算法性能很好 再加上硬件优化,这块的性能损耗很小可以忽略不计

那我们就可以把 [慢] 聚集于 TLS握手期间,我们可以将销毁总结为以下几点:

  • 握手所需的额外报文传输
  • 验证证书时 需要访问 CA 获取 CRL或OCSP
  • 非对称加密处理 Pre-Master
  • 产生用于密钥交换的临时公私钥对

image

1,加解密优化:

SSL加速卡 or SSL加速服务器: 使用专门的加速卡来分担CPU的计算压力 或者 使用 SSL加速服务器集群 [卸载] TLS握手时的加解密计算,提升加解密的速度

协议优化:
选择更快更好的密码套件,会使加解密,密钥交换过程中更加快速 例如:
性能更高的曲线:x25519
对称加密算法:AES_128 会比 AES_256 更好一点
密钥交换协议:ECDHE运算更快,安全性高,支持False Start,将握手消息往返由 2-RTT减少至 1-RTT

这些都可以在nginx的配置文件中进行设置 例如:ssl_ciphers、ssl_ecdh_curve

ssl_ciphers   TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:EECDH+CHACHA20;
ssl_ecdh_curve              X25519:P-256;

2,证书优化:

在TLS 1.2中我们有说到,服务器需要将自己的证书链发送给客户端。那这里 证书的传输 以及 证书的验证 就是性能损耗的关键点。

证书的传输: 在传输的方面,我们需要减小证书的大小,这样可以节约带宽以及减小计算量。那我们可以选择ECDHE椭圆曲线的证书,ECDHE证书(224位)相比于RSA证书(2048位)小了很多。

证书的优化: 证书在验证过程中不仅要面对繁琐的解密,如果证书撤销,客户端还需要访问CA,下载CRL或者OSCP的数据,产生DNS查询,连接建立,收发数据等一系列网络通信。

那我们可以选择将 CRL和OSCP保存起来,这样就无需进行额外的网络查询。

  • **CRL(不推荐):**CRL是定期发布的,这样会存在时间窗口的安全隐患,而且CRL中存放的是所有被吊销的证书,这个列表只会不断变大,动辄 几MB 保存CRL是不可取的
  • **OCSP Stapling:**这是OSCP的一个新补丁,原先的OCSP是在线证书状态协议,他也需要查询CA然后获取证书状态。但是OCSP Stapling 我们可以让服务器预先访问CA获取OCSP的响应,在握手的过程中将证书和OCSP查询的状态在握手时一起返回给客户端,这样就无需进行额外的查询

3,会话复用

在客户端和服务器首次连接后会各自保存一个Session ID,并且为当前会话生成一个主密钥Master。那我们能不能将主密钥Master生成这个过程跳过了,这样就跳过了证书验证和密钥交换。答案是 有的,兄弟有的

缓存SessionID(1RTT): 在第一次连接后,服务器内存保存SessionId以及当前会话的主密钥,当客户端再次连接时发送一个ID过来,就从缓存中寻找,如果找到对应的主密钥则恢复会话,并且跳过证书验证和密钥交换。

Session Ticket(1RTT): 第一种是由服务器缓存会话ID,但是对于千万级连接的服务器,这样的内存开销是十分大的。所以这个时候我们可以做一个缓存对象转换.
1,第一次访问时服务端,使用有效期的ticket密钥对Session签发的Ticket,客户端接收到后缓存Ticket。
2,客户端下一次建立连接时使用拓展 session_ticket发送 Ticket。
3,服务端获取Ticket,并进行解密校验是否有效,是否超时。如果正常则恢复会话并进行加密通信。

预共享密钥(0RTT): 在TLS1.3下,可以通过该方法达到 0RTT,在Ticket的基础上同时携带上应用数据(Early Data),这种方式叫做Pre-shared Key,检简称**PSK **
image

这样可以免去服务器确认的步骤,实现0-RTT。

相关文章:

  • 关于AI大模型的一些理解
  • 基于 Spring Boot 瑞吉外卖系统开发(一)
  • 从扩展黎曼泽塔函数构造物质和时空的结构-16
  • PyTorch 实现图像版多头注意力(Multi-Head Attention)和自注意力(Self-Attention)
  • 棋盘问题(DFS)
  • 【文献研究】含硼钢中BN表面偏析对可镀性的影响
  • 使用OpenSceneGraph生成3D数据格式文件
  • 经典回溯问题———组合的输出
  • CentOS 部署 Nodejs
  • java面试篇 Redis+MySQL+Spring
  • 【C/C++】滑动谜题(leetcode T773)
  • Transformer架构
  • 【ARTS】2873.有序三元组中的最大值!
  • c语言修炼秘籍 - - 禁(进)忌(阶)秘(技)术(巧)【第五式】动态内存管理
  • JS实现AES和DES
  • 蓝桥杯刷题周计划(第四周)
  • 手撕LLM(二):从源码出发,探索LoRA加载、推理全流程
  • AudioFramework面试题
  • 【动态规划】线性dp
  • Windows事件日志清除
  • 环保网站建设公司哪家好/百度关键词优化首选667seo
  • 做明星简介网站侵权吗/阜阳seo
  • 网站建设需要的材料/廊坊关键词快速排名
  • 个人网站怎么做cps/bt磁力在线种子搜索神器下载
  • 娄底网站建设79ld/搜索量查询百度指数
  • .net企业门户网站开发/每日新闻播报