- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
经过前两章的学习,我们知道了通信安全的定义以及TLS对其的实现~有了这些知识作为基础,我们现在可以正式的开始研究HTTPS和TLS协议了。嗯……现在才真正开始.
我记得之前大概聊过,当你在浏览器的地址栏输入一个URL地址会发生什么,大致是浏览器从URI中获取协议名和域名,获取默认端口号,再用DNS解析出IP地址,然后就可以三次握手与网站建立TCP连接了,然后就会立即进行报文的传递.
但是在HTTPS中,三次握手后,还不能立即发送报文,它还需要再用另外一个握手过程,在TCP上建立安全连接,之后才是收发HTTP报文.
这个握手过程与TCP类似,是HTTPS和TLS协议里最重要、最核心的部分,搞懂了TLS握手,你就掌握了HTTPS.
在讲TLS握手之前,我们先来了解下TLS协议的组成.
TLS 包含几个子协议,你也可以理解为它是由几个不同职责的模块组成,比较常用的有记录协议、警报协议、握手协议、变更密码规范协议等.
记录协议 (Record Protocol)规定了 TLS 收发数据的基本单位:记录(record)。它有点像是 TCP 里的 segment,所有的其他子协议都需要通过记录协议发出。但多个记录数据可以在一个 TCP 包里一次性发出,也并不需要像 TCP 那样返回 ACK.
警报协议 (Alert Protocol)的职责是向对方发出警报信息,有点像是 HTTP 协议里的状态码。比如,protocol_version 就是不支持旧版本,bad_certificate 就是证书有问题,收到警报后另一方可以选择继续,也可以立即终止连接.
握手协议 (Handshake Protocol)是 TLS 里最复杂的子协议,要比 TCP 的 SYN/ACK 复杂的多,浏览器和服务器会在握手过程中协商 TLS 版本号、随机数、密码套件等信息,然后交换证书和密钥参数,最终双方协商得到会话密钥,用于后续的混合加密系统.
最后一个是 变更密码规范协议 (Change Cipher Spec Protocol),它非常简单,就是一个“通知”,告诉对方,后续的数据都将使用加密保护。那么反过来,在它之前,数据都是明文的.
其中握手协议是最最重要的,也是本章的重点。我们先来看张简要图:
我们来分析下上图,我们可以粗略的看到三种颜色,嗯……没错,我们还可以看到两次数据的往返。嗯……也没错.
首先,图中的每一个圆角框,就是一个record,就是一个记录。多个记录可以组合成一个TCP包发送。所以最多两次往返,4个消息,就可以完成握手,然后底下的紫色部分,就是加密后的信息了.
其次,在TLS握手完成之前,也就是出现ChangeCipherSpec之前,所有的消息都是明文传输的。欸?明文传输,那不会泄露交换的数据么?这个问题我就不回答了,回忆一下我们前两章讲的东西.
最后,我们简要的看词说话一下,首先客户端会发起一个消息,携带了TLS的版本号,客户端随机数,还有一个Cipher Suites,Cipher Suites是啥呢?就是密码套件。还记得我们之前说过,客户端会把它支持的密码套件发送给服务器,让服务器来选择一个。然后呢,服务器会把一大堆东西传给客户端,其中包括TLS版本、服务器的随机数、和Cipher Suite、然后还有其它的消息,比如服务器证书Certificate,比如PubKey,就是服务器的公钥,再有就是传一个Server完事的数据。下一波呢,客户端会传一个PubKey给服务器,还有ChangeCipherSpec以及结束标记发送给服务器。服务器也返回结束。接下来就开始加密传输了.
当然,这是简单的过程,大家先消化一下,接下来我们再看看详细的流程:
嗯……这张图确实有点大。不用怕啦,我们一点一点来分析,其实这张图就是我们本章要讲的重点了,都在这张图里了.
第一部分,很好理解,我相信大家都很熟悉了,就是TCP的三次握手嘛~不说了.
TCP握手完成之后,就是第二部分,也就是第一个来回。我就不截图了,大家看上面的就好了。浏览器会首先发一个“Client Hello”消息,也就是跟服务器“打招呼”。里面有客户端的版本号、支持的密码套件,还有一个随机数(Client Random),用于后续生成会话密钥.
Handshake Protocol: Client Hello Version: TLS 1.2 ( 0x0303 ) Random: 1cbf803321fd2623408dfe… Cipher Suites ( 17 suites) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ( 0xc02f ) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ( 0xc030 )
服务器在收到”Client Hello“后,会返回一个”Server Hello“消息。把版本号对一下,也给出一个随机数(Server Random),然后从客户端的列表里选一个作为本次通信使用的密码套件,比如下面的代码选择了“TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384”.
Handshake Protocol: Server Hello Version: TLS 1.2 ( 0x0303 ) Random: 0e6320f21bae50842e96… Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ( 0xc030 )
然后,服务器为了证明自己的身份,就把证书也发给了客户端(Server Certificate).
接下来是一个关键的操作,因为服务器选择了 ECDHE 算法,所以它会在证书后发送“ Server Key Exchange ”消息,里面是 椭圆曲线的公钥 (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...
然后就是” Server Hello Done “消息,服务器的信息就传递完了.
这样,第一部分消息往返就结束了,消耗了两个TCP包,结果是客户端和服务器通过明文共享了三个信息: Client Random、Server Random、Server Params .
此刻,客户端拿到了服务器给的证书证明服务器它是它,但是客户端怎么知道这个证书是真的呢?嗯,就是我们之前讲的信任链的追溯了,确认证书的真实性后,再用证书公钥验证签名,就确认了服务器的身份.
然后,我们看第三部分,客户端按照密码套件的要求,也生产一个 椭圆曲线的公钥(Client Params) ,用“ Client Key Exchange ”消息发给服务器.
Handshake Protocol: Client Key Exchange EC Diffie - Hellman Client Params Pubkey: 8c674d0e08dc27b5eaa…
现在客户端和服务器手里都拿到了密钥交换算法的两个参数(Client Params、Server Params),就用 ECDHE 算法一阵算,算出了一个新的东西,叫“ Pre-Master ”,其实也是一个随机数。计算过程很复杂~~特别复杂,略.
现在客户端和服务器手里有了三个随机数: Client Random、Server Random 和 Pre-Master 。用这三个作为原始材料,就可以生成用于加密会话的主密钥,叫“ Master Secret ”。而黑客因为拿不到“Pre-Master”,所以也就得不到主密钥。那,为啥要三个随机数来生成Master Secret呢?其实就是为了提高破解的复杂度.
那~~再多说两句,Master-Secret怎么计算出来的呢?
master_secret = PRF(pre_master_secret, " master secret " , ClientHello.random + ServerHello.random)
这是RFC中的计算公式.
这里的“PRF”就是伪随机数函数,它基于密码套件里的最后一个参数,比如这次的 SHA384,通过摘要算法来再一次强化“Master Secret”的随机性。主密钥有 48 字节,但它也不是最终用于通信的会话密钥,还会再用 PRF 扩展出更多的密钥,比如客户端发送用的会话密钥(client_write_key)、服务器发送用的会话密钥(server_write_key)等等,避免只用一个密钥带来的安全隐患.
有了主密钥和派生的会话密钥,握手就快结束了。客户端发一个“Change Cipher Spec”,然后再发一个“Finished”消息,把之前所有发送的数据做个摘要,再加密一下,让服务器做个验证.
服务器也是同样的操作,发“Change Cipher Spec”和“Finished”消息,双方都验证加密解密 OK,握手正式结束,后面就收发被加密的 HTTP 请求和响应了.
最后,我们来看最后一部分,怎么有点奇怪呢? 客户端怎么在服务器返回握手结束的消息之前就发送HTTP加密数据了呢?
首先,我们上图中的握手过程,其实是TLS主流握手过程,这与传统的握手过程有两点不同.
第一,是使用ECDHE实现密钥交换,而不是RSA,所以会在服务器端发送”Server Key Exchange“消息.
第二,因为使用了 ECDHE, 客户端可以不用等到服务器发回“Finished”确认握手完毕,立即就发出 HTTP 报文,省去了一个消息往返的时间浪费 。这个叫“ TLS False Start” ,意思就是“ 抢跑 ”,和“TCP Fast Open”有点像,都是不等连接完全建立就提前发应用数据,提高传输的效率.
所以你看,关键就在于用了ECDHE来作为核心参数生成Master Secret.
其实到这里TLS握手的核心就基本完事了。只不过大家发现一个问题没有,上图中,只有服务器传了Certificate,让客户端验证服务器的身份。而服务器并没有验证客户端的身份。这是因为通常单向认证通过后已经建立了安全通信,用账号、密码等简单的手段就能够确认用户的真实身份.
但为了防止账号、密码被盗,有的时候(比如网上银行)还会使用 U 盾给用户颁发客户端证书,实现“双向认证”,这样会更加安全.
熟悉不?现在知道为啥你之前去银行的时候,银行会给你个U盾,在网站上操作转账啥的时候,都必须插上U盾才行,现在知道这个U盾是用来干啥的了吧?就是给你本地的电脑安装证书。当然,现在好像基本上不用U盾了,直接从可信的网站上下载证书就可以了.
双向认证的流程也没有太多变化,只是在“Server Hello Done”之后,“Client Key Exchange”之前,客户端要发送“Client Certificate”消息,服务器收到后也把证书链走一遍,验证客户端的身份。大家可以参照本章的图,自己理解一下噢~ 。
本篇,很重要,还有点复杂。大家要熟悉一下本章的两张握手图,理解TLS的握手过程。这个总结好像有点糊弄~~哈哈哈 。
哦对,大家还可以在Chrome浏览器里的Security中查看HTTPS的相关信息.
最后此篇关于真正“搞”懂HTTPS协议17之TLS握手的文章就讲到这里了,如果你想了解更多关于真正“搞”懂HTTPS协议17之TLS握手的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
是否可以使用 OpenSSL 或其他工具通过 TLS 建立 TLS 连接? 如果可能,每个级别的证书是否需要不同? 最佳答案 这在理论上应该工作得很好,但我不能确定 OpenSSL 或其他东西是否会轻
在我的 java 代码中,我正在使用命令创建 SSL 上下文的一个实例 SSLContext ctx = SSLContext.getInstance("TLS"); 但是在我的 tomcat 服务器
在我的 java 代码中,我正在使用命令创建一个 SSL 上下文实例 SSLContext ctx = SSLContext.getInstance("TLS"); 但在我的 tomcat 服务器中,
范围:这是一个具有一个 channel 的网络,该 channel 由 3 个组织组成,每个组织 1 个 anchor 节点,每个组织 1 个 CA 和每个组织 1 个 MSP。 我在我的 Hyper
无法找到用于在 iis 上启用/禁用 tls 的特定设置。启用/禁用 ssl 是否与启用/禁用 tls 相同? 我浏览了一些博客,发现 SSL 是 TLS 的前身,旧版本的 SSL 已被弃用。但我无法
最近,我一直在为基于物联网的项目评估不同的 API 网关 (API GW) 选项。这样做的目的是找到一个足够好的解决方案来执行设备和 API GW 的相互 TLS (mTLS) 身份验证。 我尝试过的
几个月来,我的 Web 应用程序在不同版本的 IE/Firefox/Chrome 上运行良好。我的应用程序在 IIS 10.0 上运行。当我从 Windows 7 框 (IE 11.0.***) 中点
我有一个在 Java 7 上运行的 HTTPS 网络服务。我需要进行更改,以便此服务仅接受 TLS1.2 连接并拒绝 SSL3、TLS1.0 和 TLS1.1。 我添加了以下 Java 参数,使 TL
我在资源管理器不显示网站时遇到问题:“无法显示此页面。在高级设置中打开 TLS 1.0、TLS 1.1 和 TLS 1.2”。 我在 chrome 中调试了证书并说“连接是使用 aes_128_cbc
我正在与 5 个订购者、1 个组织和 2 个同行建立我的网络。还有 1 个 cli 和 1 个 ca。 我从 1 个排序者扩展到 5 个实现 Raft 的排序者。这就是为什么我想扩展我的网络并对多个对
当k8s集群开启了TLS认证后,每个节点的kubelet组件都要使用由kube-apiserver的CA签发的有效证书才能与kube-apiserver通信;当节点非常多的时候,为每个节点都单独签署证
我正在尝试使用 pjsip 安装中的 pjsua 程序在两个虚拟机之间进行安全调用。我通过以下方式在每个节点上启动程序: pjsua-x86_64-unknown-linux-gnu --use-tl
我开发的软件应用程序使用 gRPC 在客户端和服务器之间建立双向流。 我只在 java 中寻找类似于这张票的答案的东西:How to enable server side SSL for gRPC?
我正在尝试调试与 TLS 相关的问题。TLS 在两个应用程序客户端 A 和服务器 B 之间设置。A 和 B 都交换了证书,我已经验证证书具有正确的扩展名,并且还通过其根 CA 成功验证。叶证书的根 C
“Java 1.7 TLS 1.1 服务器”和“Java 1.8 客户端”之间的 SSL/TLS 握手在我的环境中失败,服务器端出现以下异常: java.security.NoSuchAlgorith
我正在尝试了解 Docker ,但我不断收到神秘的(对我而言)错误消息。 可能最简单的例子是尝试打印我安装的 Docker 版本: $ sudo docker version Client versi
这是我第一次使用 Amazon Lighsail、Wordpress Multisite、Bitnami甚至使用 Let's Encrypt;现在似乎一切正常,除了我的虚拟主机文件中的 SSL 指令。
我有一个 MariaDB "M"。在同一台机器上有一个应用程序“A”,它可以访问它。在不同的服务器上,另一个应用程序“B”也在访问它。 现在我想在 MariaDB 上启用 TLS 以保护连接 B ->
我正在寻找通过代理连接到一些 HTTPS/TLS 站点,其中到代理本身的连接也是通过 HTTPS/TLS 建立的,来自一个高度依赖请求的 python 应用程序。 urllib3(因此 request
现在我正在努力改变 EMQtt 和 Erlang MQTT 代理,以便我可以使用预共享 key 而不是非对称方法执行 TLS 握手。 到目前为止,我几乎遍历了源代码中的每个文件,但找不到任何加密函数。
我是一名优秀的程序员,十分优秀!