TCP和SSL/TLS 协议通信原理

本文讲述了在OAuth2单点登录中遇到的客户端使用SSLv3与服务端TSL1.2不兼容的问题,通过解析SSL/TLS协议通信原理,包括握手流程和协议版本确认,以及如何通过修改客户端代码解决此问题。
摘要由CSDN通过智能技术生成

👽System.out.println(“👋🏼嗨,大家好,我是代码不会敲的小符,双非大四,Java实习中…”);
📚System.out.println(“🎈如果文章中有错误的地方,恳请大家指正!共同进步,共同成长✊”);
🌟System.out.println(“💡如果文章对您有所帮助,希望您可以三连支持一下博主噢🔥”);
🌈System.out.println("🚀正在完成计划中:接下来的三个月里,对梦想的追逐 ");

背景

产品提了一个bug,初步排查可能是因为对接oAuth2单点登录时,客户端使用的https协议和服务端的使用的https协议版本不相同。客户端使用的协议版本是SSLv3,服务端使用使用的协议版本是TSL1.2。所以上午补了一下关于https的SSL/TLS的基础知识

问题及解决: a网站向b网站请求授权。a网站看作客户端;b网站看作服务端:授权服务器
客户端携带授权码等信息会向授权服务器发送一个请求获取token,在安全层建立SSL/TSL协议通信时 授权服务器会验证客户端的协议版本、加密算法等信息
原因: TLS1.2和SSLv3都是基于相同的基础协议设计的,但在加密算法、握手流程和消息格式方面存在一些差异,不能完全兼容
解决: 修改客户端代码中的协议版本为的SSL(SSL:支持某些版本的SSL;可能支持其他版本);第一次握手会话客户端向服务端发送支持的协议版本、加密算法等,第二次握手会话服务端会确认使用匹配的协议版本、协议版本等。确保服务端和客户端能够兼容。

关于HTTP和HTTPS

访问网站时,以HTTPS开头的表示你和服务器之间传输的数据经过了加密,这里所使用的加密协议就是SSL(Secure Sockets Layer,后来又推出了它的后续版本,改名叫TLS)。把HTTP协议经过一层SSL协议进行加密包装,就变成了HTTPS。当然,SSL/TLS还用在很多协议中,例如VPN、加密的电子邮件协议等。
image.png
image.png
SSL(Secure Socket Layer)安全套接层
TLS(Transport Layer Security)传输层安全协议(SSL的后续版本)
TLS的主要目标是使SSL更安全,并使协议的规范更精确和完善。TLS 在SSL v3.0 的基础上,提供了以下增强内容:

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

SSL/TSL

jdk1.8默认为TSL1.2
OPENSSL
在SSL协议中,我们使用了很多密码学手段来保护数据,其中包括对称密码、公钥密码、数字签名、证书、完整性校验、伪随机数生成等。OpenSSL是一套开源的密码学工具包(open source cryptography toolkit),是一个强大的安全套接字层密码库,囊括主要的密码算法、常用的密钥和证书封装管理功能及 SSL 协议,并提供丰富的应用程序供测试或其他的目的使用。

  • Libencrpt:加解密库
  • Libssl:实现ssl安全通信机制的库
  • Openssl:多用途命令行工具

SSL/TSL 协议通信原理

会话握手的四个阶段,"握手阶段"的所有通信都是明文的
image.png

  1. 客户端发出请求(ClientHello):客户端(通常是浏览器、sso的客户端)先向服务器发出加密通信的请求,这被叫做ClientHello请求。在这一步,客户端主要向服务器提供以下信息
  • 产生一个随机数,这个随机数一方面需要在客户端保存,另一方面需要传送给服务端

    1. 支持的协议版本,比如TLS 1.2版。
    2. 一个客户端生成的随机数,稍后用于生成"对话密钥"。
    3. 支持的加密方法,比如RSA公钥加密。
    4. 支持的压缩方法。

注意: 客户端发送的信息之中不包括服务器的域名。也就是说,理论上服务器只能包含一个网站,否则会分不清应该向客户端提供哪一个网站的数字证书。这就是为什么通常一台服务器只能有一张数字证书的原因。

  1. 服务器回应(SeverHello):服务器收到客户端请求后,向客户端发出回应,这叫做SeverHello。服务器的回应包含以下内容。
  • 服务端也需要产生一个随机数发送给客户端。客户端和服务端都需要使用这两个随机数来产生 Master Secret

    1. 确认使用的加密通信协议版本,比如TLS 1.0版本。如果浏览器与服务器支持的版本不一致,服务器关闭加密通信。
    2. 一个服务器生成的随机数,稍后用于生成"对话密钥"。
    3. 确认使用的加密方法,比如RSA公钥加密。
    4. 服务器证书。(如X509)
    5. 索要客户端证书(非必须),银行金融系统会需要,其它很少有网点会索取
  1. 客户端回应:客户端收到服务器回应以后,首先验证服务器证书。如果证书不是可信机构颁布、或者证书中的域名与实际域名不一致、或者证书已经过期,就会向访问者显示一个警告,由其选择是否还要继续通信。如果证书没有问题,客户端就会从证书中取出服务器的公钥。然后,向服务器发送下面三项信息。
    1. 一个随机数。该随机数用服务器公钥加密,防止被窃听。
    2. 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。
    3. 客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供服务器校验。

上面第一项的随机数,是整个握手阶段出现的第三个随机数,又称"pre-master key"。有了它以后,客户端和服务器就同时有了三个随机数【三个随机数通过一个密钥导出器最终导出一个对称密钥。安全性】,接着双方就用事先商定的加密方法,各自生成本次会话所用的同一把"会话密钥"。

  1. 服务器的最后回应:服务器收到客户端的第三个随机数 pre-master key 之后,计算生成本次会话所用的"会话密钥"。然后,向客户端最后发送下面信息。
    1. 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。
    2. 服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供客户端校验。

至此,整个握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的HTTP协议,只不过用"会话密钥"加密内容。
image.png

TCP三次握手建立连接

image.png
一开始,客户端和服务端都处于 CLOSE 状态。先是服务端主动监听某个端口,处于 LISTEN 状态

  1. 客户端会随机初始化序号(client_isn),将此序号置于 TCP 首部的「序号」字段中,同时把 SYN 标志位置为 1,表示 SYN 报文。接着把第一个 SYN 报文发送给服务端,表示向服务端发起连接,该报文不包含应用层数据,之后客户端处于 SYN-SENT 状态。
  2. 服务端收到客户端的 SYN 报文后,首先服务端也随机初始化自己的序号(server_isn),将此序号填入 TCP 首部的「序号」字段中,其次把 TCP 首部的「确认应答号」字段填入 client_isn + 1, 接着把 SYN 和 ACK 标志位置为 1。最后把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于 SYN-RCVD 状态。
  3. 客户端收到服务端报文后,还要向服务端回应最后一个应答报文,首先该应答报文 TCP 首部 ACK 标志位置为 1 ,其次「确认应答号」字段填入 server_isn + 1 ,最后把报文发送给服务端,这次报文可以携带客户到服务端的数据,之后客户端处于 ESTABLISHED 状态。

服务端收到客户端的应答报文后,也进入 ESTABLISHED 状态。第三次握手是可以携带数据的,前两次握手是不可以携带数据的

TCP四次挥手

  • 关闭连接时,客户端向服务端发送 FIN 时,仅仅表示客户端不再发送数据了但是还能接收数据。
  • 服务端收到客户端的 FIN 报文时,先回一个 ACK 应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送 FIN 报文给客户端来表示同意现在关闭连接。

image.png

  1. 客户端打算关闭连接,此时会发送一个 TCP 首部 FIN 标志位被置为 1 的报文,也即 FIN 报文,之后客户端进入 FIN_WAIT_1 状态。
  2. 服务端收到该报文后,就向客户端发送 ACK 应答报文,接着服务端进入 CLOSE_WAIT 状态。
  3. 客户端收到服务端的 ACK 应答报文后,之后进入 FIN_WAIT_2 状态。
  4. 等待服务端处理完数据后,也向客户端发送 FIN 报文,之后服务端进入 LAST_ACK 状态。
  5. 客户端收到服务端的 FIN 报文后,回一个 ACK 应答报文,之后进入 TIME_WAIT 状态
  6. 服务端收到了 ACK 应答报文后,就进入了 CLOSE 状态,至此服务端已经完成连接的关闭。
  7. 客户端在经过 2MSL 一段时间后,自动进入 CLOSE 状态,至此客户端也完成连接的关闭。

每一个方向都需要一个 FIN 和一个 ACK,因此通常被称为四次挥手。
注意:主动关闭连接的,才有 TIME_WAIT 状态

参考文章:
SSL/TLS原理详解
一篇文章读懂HTTPS TLS 1.2握手流程(中)
一文看懂SSL/TLS/OPENSSL/HTTPS

最后

慢慢的来,别着急!学会有质量的走过每一步


我是代码不会敲的小符,希望认识更多有经验的大佬,也在努力摸索出自己的道路
欢迎添加小符微信:A13781678921,一起加油

  • 24
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
使用 `socket_set_option` 函数设置 SSL/TLS 加密通信需要先创建一个 SSL/TLS 上下文,然后将该上下文应用到 socket 上。具体的步骤如下: 1. 创建一个 SSL/TLS 上下文,可以使用 OpenSSL 库提供的函数进行创建,比如 `openssl_pkey_new`、`openssl_x509_read`、`openssl_pkcs12_read` 等。 2. 使用 `stream_context_create` 函数创建一个上下文,将 SSL/TLS 上下文作为参数传入。 3. 使用 `stream_socket_enable_crypto` 函数将 SSL/TLS 上下文应用到 socket 上,使其支持 SSL/TLS 加密通信。 下面是一个使用 `socket_set_option` 函数设置 SSL/TLS 加密通信的示例代码: ```php $server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); socket_set_option($server, SOL_SOCKET, SO_REUSEADDR, 1); // 创建 SSL/TLS 上下文 $sslContext = stream_context_create(); stream_context_set_option($sslContext, 'ssl', 'local_cert', '/path/to/cert.pem'); stream_context_set_option($sslContext, 'ssl', 'local_pk', '/path/to/private/key.pem'); // 将 SSL/TLS 上下文应用到 socket 上 stream_socket_enable_crypto($server, true, STREAM_CRYPTO_METHOD_TLS_SERVER, $sslContext); ``` 在上面的示例代码中,我们使用了 `stream_context_create` 函数创建了一个上下文 `$sslContext`,并使用 `stream_context_set_option` 函数设置了 SSL/TLS 上下文的相关参数,包括证书路径、私钥路径等。然后,我们使用 `stream_socket_enable_crypto` 函数将 SSL/TLS 上下文 `$sslContext` 应用到 socket `$server` 上,使其支持 SSL/TLS 加密通信。 需要注意的是,在使用 SSL/TLS 加密通信时,客户端和服务端都需要支持 SSL/TLS,否则无法建立加密通信。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

代码不会敲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值