TLS 简单解释

TLS 的必要性

想象一下你坐在一家咖啡厅,连着咖啡厅的免费 Wi-Fi。你打开淘宝网开始购物,并且输入你的支付宝账号密码完成支付。然而此时这个世界上还没有 TLS/SSL 技术,你的淘宝网使用 HTTP 协议传输数据,这是一种明文传输协议,你向淘宝网发送的账号密码全被咖啡厅老板的路由器记录了下来。三天后,你收到一条短信,上面写着你支付宝账户中的 500 万被转入了咖啡厅老板的账户。

sequenceDiagram participant 你 participant 路由器 participant 淘宝网 Note over 你: 你输入支付宝账号密码进行支付 你->>路由器: 带有账号密码的 HTTP 请求<br>(明文数据) Note right of 路由器: 路由器拦截请求<br>并记录账号密码 路由器->>淘宝网: 转发请求

显然,我们需要一种技术,能将我们发送的数据加密,不让咖啡厅老板知道我们发送的内容。那么怎么做呢?

TLS 的原理

这个问题可以抽象为一种加密信件邮寄问题:你要给朋友寄一封信,但是不希望邮寄员看到信的内容。

怎么解决呢?很容易想到的方法是,你将信装到一个保险箱里,再把保险箱交给邮寄员进行邮寄。

sequenceDiagram participant 你 participant 邮寄员 participant 朋友 Note over 你: 你将信件装入保险箱 你->>邮寄员: 将装有信件的保险箱送给邮寄员 Note over 邮寄员: 邮寄员无法开锁,因此无法窃取信件 邮寄员->>朋友: 将完好无损的保险箱送给朋友 Note over 朋友: 朋友使用密码打开保险箱获取信件

然而朋友需要你的密码才能开锁。怎么把密码告诉他呢?显然不能直接通过信件邮寄,不然邮寄员就知道我们的密码了。朋友说,他可以先寄给你一个打开着的锁箱,你把密码信放到锁箱里,关好锁箱再寄给他,这样他就能拿到密码了。

sequenceDiagram participant 你 participant 邮寄员 participant 朋友 Note over 朋友: 制作一个锁箱,并将钥匙留在自己手里 朋友->>邮寄员: 将打开着的锁箱送给邮寄员 Note over 邮寄员: 假设邮寄员不会掉包锁箱 邮寄员->>你: 将完好无损的锁箱送给你 Note over 你: 你装入密码信并关闭锁箱 你->>邮寄员: 将装有密码信的锁箱送给邮寄员 Note over 邮寄员: 邮寄员无法开锁,因此无法窃取密码信 邮寄员->>朋友: 将完好无损的锁箱送给朋友 Note over 朋友: 朋友使用钥匙开锁获取密码信 alt 朋友得到密码 Note over 你: 你将信件装入保险箱,<br>并使用之前的密码上锁 你->>邮寄员: 将装有信件的保险箱送给邮寄员 邮寄员->>朋友: 将完好无损的保险箱送给朋友 Note over 朋友: 朋友使用密码打开保险箱获取信件 end

然而这里有一个问题:如果邮寄员掉包了朋友的锁箱,导致我们收到的锁箱实际上来自于邮寄员,那么邮寄员就可以窃取密码信了。那么,如何确保收到的锁箱来自于朋友呢?

朋友想了个办法,说:他可以在锁箱上刻下自己的名字,然后把锁箱带到公证处去盖章。他再将盖有公章的锁箱寄给我。如果我收到的锁箱刻有他的名字,并盖有公证处的公章,那么就证明这个锁箱来自于他。这样我们就可以放心地用收到的锁箱装密码信了。

sequenceDiagram participant 你 participant 邮寄员 participant 朋友 participant 公证处 Note over 朋友: 制作一个锁箱,并将钥匙留在自己手里<br>然后在锁箱上刻下自己的名字 朋友->>公证处: 将刻有名字的锁箱送给公证处 Note over 公证处: 验证朋友的身份,然后在锁箱上盖章 公证处->>朋友: 将盖有公章的锁箱送给朋友 朋友->>邮寄员: 将盖有公章的锁箱送给邮寄员 Note over 邮寄员: 邮寄员无法掉包锁箱,<br>因为锁箱上有朋友的名字和公章 邮寄员->>你: 将完好无损的锁箱送给你 Note over 你: 看到锁箱上有朋友的名字和公章,证明锁箱来自朋友<br>你装入密码信并关闭锁箱 你->>邮寄员: 将装有密码信的锁箱送给邮寄员 Note over 邮寄员: 邮寄员无法开锁,因此无法窃取密码信 邮寄员->>朋友: 将完好无损的锁箱送给朋友 Note over 朋友: 朋友使用钥匙开锁获取密码信 alt 朋友得到密码 Note over 你: 你将信件装入保险箱 你->>邮寄员: 将装有信件的保险箱送给邮寄员 Note over 邮寄员: 邮寄员不知道密码,无法打开保险箱 邮寄员->>朋友: 将完好无损的保险箱送给朋友 Note over 朋友: 朋友使用密码打开保险箱获取信件 end

好了现在想象结束,回到现实世界。现实世界有一种叫“非对称加密”的技术,这种技术会创建一个密钥对,其中一个叫私钥,另一个叫公钥。这个密钥对有这样的特点:公钥加密的文件只能由私钥解密,而私钥加密的文件只能由公钥解密。通过这个密钥对,我们可以实现“加密”和“签名”两种功能。

  • 加密:我们可以想象公钥就是“锁箱”,私钥就是锁箱的钥匙。被锁箱锁住(公钥加密)的文件必须用锁箱的钥匙才能取出(私钥解密)。

  • 签名:我们可以想象私钥就是公证处的公章,公钥就是能够验证公证处公章的机器。只有盖有公证处公章(私钥加密)的文件才能通过机器的验证(公钥解密)。

    在互联网中,持有“公章”的机构叫“证书颁发机构”(Certificate Authority, CA)。每台电脑在出厂时都预装了多家可信 CA 的公钥。这样,我们就可以验证任何公章(签名)是否来自于可信 CA。

在咖啡厅购物问题中,我们希望发送给淘宝的消息(账号密码)不被咖啡厅的路由器窃取。因此,淘宝网首先将网站的公钥和域名发送给 CA,CA 在验证淘宝网的身份之后对公钥和域名签名。我们将签名后的公钥和域名视作一个整体,叫做证书。淘宝网将证书发送给我们,我们收到证书后通过预装的 CA 公钥验证证书中的签名,如果验证成功,说明证书由 CA 颁发,且我们相信 CA 已经验证了证书中域名和公钥的真实性。因此我们可以用其中的公钥加密通讯密码,然后将加密过的密码发送给淘宝网。淘宝网在获取到密码之后,我们就可以用它作为对称加密的密码来传递消息了。

这里你可能会问:既然非对称加密技术已经可以用来加密通信,为什么我们不直接用非对称加密来进行通信,而要交换密码,再用密码来进行对称加密通信呢?

原因是,非对称加密技术的加解密速度要远慢于对称加密。所以我们一般用非对称加密技术来交换密码,在交换密码之后再使用对称加密来进行通信。

信任链

通过上面的例子你会发现,我们的通讯是否安全,实际上完全取决于 CA 是否可信。如果 CA 只为真实的公钥和域名颁发证书,那么我们的通讯安全就能够得到保障。相反,如果 CA 为虚假的公钥和域名颁发证书,那么中间人(比如咖啡厅老板的路由器)就能够用虚假证书窃取我们的密码,从而窃听后续的对称加密消息。所以,我们必须只安装可信 CA 的公钥,这样才能确保通信不被窃听。现实中,可信 CA 的公钥实际上也是保存到证书里来进行分发的。由于这个证书是整个信任链的起点,因此它有个特殊的名字,叫“根证书”。

如果全世界只有一个 CA 颁发证书,那么一旦这个 CA 的私钥泄露,那么整个互联网的安全体系都将崩溃。因此为了减小风险,现实世界使用了多层 CA 的办法:Root CA 给 Intermediate CA 颁发证书,Intermediate CA 再给 Issuing CA 颁发证书,Issuing CA 再给网站颁发证书。在 TLS 握手时,我们收到所有这些 CA 颁发的证书。只要我们的电脑上安装了 Root CA 的根证书,那么就能用证书中 Root CA 的公钥验证 Root CA 颁发给 Intermediate CA 的证书是真实的,从而可以信任证书中 Intermediate CA 的公钥。再用 Intermediate CA 的公钥验证 Intermediate CA 颁发给 Issuing CA 的证书,从而信任证书中 Issuing CA 的公钥。然后用 Issuing CA 的公钥验证 Issuing CA 颁发给网站的证书,从而信任网站证书中网站的公钥。最后用网站的公钥加密我们的消息。

在这个过程中,如果某个中间 CA 的私钥发生泄露,上层 CA 可以马上吊销颁发给中间 CA 的证书,从而保障整个信任链的安全。

graph TD; A[Root CA] --> B[Intermediate CA 1]; A --> C[Intermediate CA 2]; B --> D[Issuing CA 1]; B --> E[Issuing CA 2]; C --> F[Issuing CA 3]; C --> G[Issuing CA 4]; D --> H[终端用户证书]; E --> I[终端用户证书]; F --> J[终端用户证书]; G --> K[终端用户证书];

MitM 攻击

在信任链一节中我们讲了只有安装可信 CA 的根证书才能确保通信的安全。那么如果安装了不可信 CA 的根证书会怎么样呢?这就使得中间人攻击成为可能(Man-in-the-Middle attack)。

回到加密信件邮寄问题,现在我们假设邮寄员家里手眼通天,邮寄员自己开了一家公证处。在你和朋友准备通信时,朋友还是像往常一样,先去公证处给自己的锁箱盖章,然后将锁箱送给邮寄员。邮件员拿到锁箱后,并没有直接送给你,而是自己仿制了一个锁箱,刻上朋友的名字,再到自己家的公证处盖章,然后将仿制的锁箱送给你。你拿到锁箱之后,看到锁箱上刻有朋友的名字,还盖有公证处的公章,所以你认为这个锁箱来自于朋友,于是便放心地把密码信装进去了。之后,你将锁箱关好,并交给邮寄员进行邮寄。然而,邮寄员拥有仿制锁箱的钥匙,因此他打开了锁箱,拿到里面的密码信,将密码照抄一份后装入了朋友的锁箱。然后,邮寄员再将朋友的锁箱送给朋友。你和朋友没有意识到密码已经被邮寄员窃取,按照约定,你们使用保险箱传输后续的信件。但是此时邮寄员已经可以中途打开你们的保险箱查看里面的信件了。

sequenceDiagram participant 你 participant 邮寄员 participant 朋友 Note over 朋友: 制作一个锁箱,并将钥匙留在自己手里<br>然后在锁箱上刻下自己的名字并带到公证处盖章 朋友->>邮寄员: 将盖有公章的锁箱送给邮寄员 Note over 邮寄员: 邮寄员将朋友的锁箱藏起来,<br>并仿制了一个锁箱,然后盖上自家公证处的公章 邮寄员->>你: 将仿制锁箱送给你 Note over 你: 看到锁箱上有朋友的名字和公章,以为锁箱来自朋友<br>你装入密码信并关闭锁箱 你->>邮寄员: 将装有密码信的锁箱送给邮寄员 Note over 邮寄员: 邮寄员使用钥匙打开仿制锁箱取出密码信,<br>将密码信抄写一份后装入朋友的锁箱 邮寄员->>朋友: 将锁箱送给朋友 Note over 朋友: 朋友使用钥匙开锁获取密码信 alt 朋友得到密码 Note over 你: 你将信件装入保险箱 你->>邮寄员: 将装有信件的保险箱送给邮寄员 Note over 邮寄员: 邮寄员使用抄写的密码打开保险箱偷看信件内容 邮寄员->>朋友: 将保险箱送给朋友 Note over 朋友: 朋友使用密码打开保险箱获取信件 end

可以看到,密码信泄露的根本原因是你信任了邮寄员开的公证处,从而导致邮寄员可以仿制任何锁箱并在邮寄的途中偷天换日。

现实中的网络分析工具就是通过这种方法来解密 HTTPS 内容的。你只要安装了网络分析工具生成的根证书,那么在 TLS 握手阶段,网络分析工具就能通过伪造目标服务器的证书来欺骗系统建立 HTTPS 通信,窃取通信密钥,从而监听整个会话。

TLS 握手流程

真实的 TLS 1.1 握手流程如下:

sequenceDiagram participant 客户端 participant 服务器 客户端->>服务器: ClientHello<br>(协议版本、随机数、支持的加密套件) 服务器->>客户端: ServerHello<br>(协议版本、随机数、选择的加密套件) 服务器->>客户端: 证书<br>(服务器公钥) 服务器->>客户端: ServerHelloDone<br>(握手消息结束) 客户端->>服务器: PreMasterSecret<br>(使用服务器公钥加密) 客户端->>客户端: 生成 MasterSecret<br>(使用 PreMasterSecret 和随机数) 服务器->>服务器: 生成 MasterSecret<br>(使用 PreMasterSecret 和随机数) 客户端->>服务器: ChangeCipherSpec<br>(通知切换到加密通信) 客户端->>服务器: Finished<br>(加密的握手摘要) 服务器->>客户端: ChangeCipherSpec<br>(通知切换到加密通信) 服务器->>客户端: Finished<br>(加密的握手摘要) Note over 客户端,服务器: 安全通信通道建立完成

这里的 Pre-Master Secret,就是我们例子中的密码信。不过后续加密通信使用的 Master Secret 还需使用 Pre-Master Secret 生成出来,并不是直接使用 Pre-Master Secret。

参见:

posted @ 2025-01-01 22:36  Undefined443  阅读(21)  评论(0编辑  收藏  举报