此篇文章灵感来自于李永乐老师区块链防伪加密的讲解。传送门
ssl/tls 协议是什么?
SSL(Secure Sockets Layer 安全套接层)是一种标准安全协议,旨在 两个通信应用程序 之间安全交换信息(加密)。
那 TLS 又是什么?Transport Layer Security (TLS)是SSL协议的升级版,TLS 1.0通常被标示为SSL 3.1,TLS 1.1为SSL 3.2,TLS 1.2为SSL 3.3。现在习惯将这个两个组合在一起称为 SSL/TLS,只要知道它是一种用于加密的安全协议就好了。
ssl/tls 的位置
SSL介于应用层和传输层之间。应用层数据不再直接传递给传输层,而是传递给SSL层,SSL层对从应用层收到的数据进行加密,并增加自己的SSL头。
不使用SSL/TLS的HTTP通信,就是不加密的通信。所有信息明文传播,带来了三大风险。
(1) 窃听风险(eavesdropping):第三方可以获知通信内容。
(2) 篡改风险(tampering):第三方可以修改通信内容。
(3) 冒充风险(pretending):第三方可以冒充他人身份参与通信。
SSL/TLS协议是为了解决这三大风险而设计的,希望达到:
(1) 所有信息都是加密传播,第三方无法窃听。
(2) 具有校验机制,一旦被篡改,通信双方会立刻发现。
(3) 配备身份证书,防止身份被冒充。
HTTPS 经由 HTTP 进行通信,但利用 SSL/TLS 来加密数据包。
💥所以,ssl/tls + http(超文本传输协议) = https(超文本传输安全协议)
https 运行的基本过程
一、ssl/tls 协议执行握手阶段(非对称加密)
握手阶段分成五步:
-
第一步,客户端给出tls协议版本号、一个客户端生成的随机数(Client random),以及客户端支持的加密方法。
-
第二步,服务器确认双方使用的加密方法,并给出数字证书、以及一个服务器生成的随机数(Server random)。
-
第三步,客户端确认数字证书有效,然后生成一个新的随机数(Premaster secret),并使用数字证书中的公钥,加密这个随机数,发给服务器。
-
第四步,服务器使用自己的私钥,获取客户端发来的随机数(即Premaster secret)。
-
第五步,客户端和服务器根据约定的加密方法,使用前面的三个随机数,生成"对话密钥"(session key),用来加密接下来的整个对话过程。
二、握手结束,使用 http 协议通信,采用"对话密钥"加密消息(对称加密)
整个握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的HTTP协议,只不过用"会话密钥"加密内容。
服务器私钥的作用
握手阶段有三点需要注意。
-
生成对话密钥一共需要三个随机数。
-
握手之后的对话使用 "对话密钥" 加密(对称加密),服务器的公钥和私钥只用于加密和解密"对话密钥"(非对称加密),无其他作用。
-
服务器公钥放在服务器的数字证书之中。
从上面第二点可知,整个对话过程中(握手阶段和其后的对话),服务器的公钥和私钥只需要用到一次。
举个例子:
某些客户(比如银行)想要使用外部CDN,加快自家网站的访问速度,但是出于安全考虑,不能把私钥交给CDN服务商。这时,完全可以把私钥留在自家服务器,只用来解密对话密钥,其他步骤都让CDN服务商去完成。
上图中,银行的服务器只参与第四步,后面的对话都不再会用到私钥了。
所以 CloudFlare 提供的 Keyless 服务,即你把网站放到它们的CDN上,不用提供自己的私钥,也能使用 SSL 加密链接。
DH算法的握手阶段
整个握手阶段都不加密(也没法加密),都是明文的。因此,如果有人窃听通信,他可以知道双方选择的加密方法,以及三个随机数中的两个。整个通话的安全,只取决于第三个随机数(Premaster secret)能不能被破解。
虽然理论上,只要服务器的公钥足够长(比如2048位),那么Premaster secret可以保证不被破解。但是为了足够安全,我们可以考虑把握手阶段的算法从默认的RSA算法,改为 Diffie-Hellman算法(简称DH算法)。
采用DH算法后,Premaster secret不需要传递,双方只要交换各自的参数,就可以算出这个随机数。
上图中,第三步和第四步由传递Premaster secret变成了传递DH算法所需的参数(Server DH paramerter & Client DH parameter),然后双方各自算出Premaster secret。这样就提高了安全性。
为什么这么说呢?
因为就算中间人拿到了 server 以及 client 的 DH 参数,也无法计算出第三个随机数(Premaster secret)。
请看下图,DH 算法的是利用以下原理,截自DH算法:(爱丽丝与鲍伯分别代表客户端与服务器)
相关问题
客户端如何验证数字证书?
数字签名防止数据被篡改。
服务器的数字证书(digital certificate) 中包含了服务器的公钥、组织信息、有效时间、证书序列号等明文信息,同时包含一个 CA 生成的数字签名。
证书签名过程:
-
CA 使用 Hash 函数来计算服务器提交的明文信息,并得出信息摘要(digest);
-
CA 再使用私钥对信息摘要进行加密,加密后的密文就是 CA 颁发给服务器的 数字签名。盖章啦😁
在客户端与服务器ssl握手时,服务器向客户端发送数字证书。
客户端验证过程:
- 客户端读取证书中的明文信息,采用 CA 签名时相同的 Hash 函数来计算并得到 信息摘要A;
- 客户端再利用 CA 公钥来解密签名数据,得到 信息摘要B。
- 对比信息摘要 A 和信息摘要 B,如果一致证书是合法的。
- 同时客户端还会验证证书相关的域名信息、有效时间等。
下图是服务器向客户端发送信息、签名与验证的过程,与 CA 证书验证大致相同:
私钥数字签名;公钥解密签名。最终验证摘要
由上图可以看到,最终验证摘要是否相同,相同则信息未被修改过。
关于数字签名更详细介绍请跳转这里。
关于 tls 版本问题
两个通信应用程序(服务器<=>服务器,浏览器<=>服务器等等)之间必须保证 tls 支持的版本一致性,若不一致被请求一方关闭加密通信。
实际开发中遇到的情况:
- 环境:node v12,bird,server1(support tls v1.0) server2(support tls v1.0 tls v1.1 tls v1.2 tls v1.3)
bird 为本地node开发代理服务器
- 问题描述:
本地启动 bird 去连接 server2,一切正常访问。
本地启动 bird 去连接 server1,发现如下问题:
-
问题分析:
- node v11.4之后对 tls 最小支持的版本为 v1.2
- server1 仅支持 tls v1.0
版本支持不一致,服务器关闭加密通信。
-
解决方案:
第一种:启动 bird(node) 时, 添加 --tls-min-v1.0
, 使 node 支持的最小版本为 v1.0。
node --tls-min-v1.0 run.js
第二种:node 降级至 11.4 以下。
第三种:server 支持 tls 高版本。
参考
- 图解SSL/TLS协议 by 阮一峰
- SSL协议详解
- ssl/tls是什么?是怎么工作的?
- SSL/TLS协议运行机制的概述 by 阮一峰