引子

HTTPS在我们的日常生活中已经司空见惯,特别是有时我们会遇到这种页面:

1

这是什么意思呢?这个来自浏览器的提示意味着我们访问的 HTTPS 页面并不安全. 那为什么会不安全呢?是因为其网站的证书出现问题了.

那么什么是证书?为什么我们需要证书来保证安全?接下来我们将一一说明.

与之前的 DNS 文章联系一下,二者都是在应用层工作的协议.DNS 的高级过程例如 DoH就采用了 HTTPS 来传输查询结果.

通常访问某个域名的过程中,先用 DNS 解析 IP 地址, 再用 HTTP 协议向该地址发起请求,例如 GET,POST等,最后服务器响应网页内容. 这个过程我们先在脑子中有个印象,后面大多围绕这个过程展开.

为什么需要HTTPS

HTTPS 故名思义,HTTP over SSL(TSL),是在 HTTP 协议上加了一层 SSL(什么是SSL我们稍后解释)

众所周知,HTTP 传输的报文是明文传输,在之前 DNS 那篇文章中我们就说 DNS 查询过程是明文传输, 为了保证安全后面采用了 DoT 与 DoH,其中 DoH 就是 DNS over https.

所以为了保证安全,使我们传输的报文变得不那么透明,我们需要给他加上一层保护,这层保护就是 SSL. 可以阻止其他人嗅探我们的报文,获取我们的报文内容等等不当操作.

2

如果没有 SSL,光用 HTTP 行不行呢?举一些例子来说明:

  • 中间人攻击:如果我们使用 HTTP 进行登陆某个网站,攻击者可以看到其中的内容,那么你的用户名和密码就泄漏了.
  • 内容篡改:同样的,攻击者或者 ISP 可以偷偷修改网页内容例如插入广告
  • 钓鱼网站:访问银行网站,但是攻击者将你的请求重定向(例如DNS劫持)到假的网站,内容是复制真的网站,从而误导你进行错误操作.

所以我们需要 SSL !

什么是SSL(TLS)

我们上面提到单纯的 HTTP 会遇到嗅探等攻击,所以我们要为它创造一条隧道,一条受保护的隧道,这就是 SSL 的目的. Secure Socket Layer

一个安全的,受到 SSL 保护的网站是这样的

3

SSL 可以做到的是

  • 加密通信:防止中间人窃听
  • 身份验证:防止钓鱼网站
  • 完整性校验:数据不被篡改

在解释什么是 SSL 之前,我觉得我们需要先了解一些其他概念,辅助我们后续理解.

  • 证书与CA
  • 密钥与加密

什么是证书与CA

正如上面钓鱼网站的例子,网站怎么能够证明他是真的网站,是我们要访问的网站呢?

举例说明

仿照别人的例子来说:

你是A公司的员工,带着一封信要访问B公司,到门口保安室的时候信上带有A公司的公章,由于B公司信任A公司的公章,所以接受这封信.(先不提伪造公章这种事) 这里的公章就是证书的感觉,钓鱼网站一般没有这种证书,所以我们可以知道这是假的网站.

如果有D,E等等很多公司,B公司也都信任他们,可是这对保安来说是一个坏消息,这么多不同公司的公章,我该怎么认全呢? 所以这时有一个C公司出场了,他是一个中介公司,专门处理代理公章业务——B公司必须信任C公司

之后A公司再访问B公司情况就变成了这样:A公司携带两封信访问B公司,第一封信上有C公司的公章和A公司的公章,保安看见后, 他只识别C公司的公章,正确,看第二封信.第二封信上有一个A公司的公章,和第一封信上的一对比,发现一致,保安接受第二封信.

可以发现,对于其他公司也是一样,多带一封信来验证身份,B公司的保安只需要知道C公司的公章即可,然后对比一二封信的公司公章进行验证.

这个例子最后的C公司就是 CA 证书颁发机构(Certificate Authority),正如例子中所言,他是一个双方都可以完全信任的机构. 常见的 CA 包括 DigiCert,Let’s Encrypt(免费),Secigo 等;常见的 CA 工具包括:OpenSSL,EasyRSA,CFSSL等.

回到我们访问网站的例子,如果我们访问某个 https 网站,浏览器就会去验证这个网页的 CA证书, 如果这个证书没有问题,那么我们就知道这个网站就是我们要访问的网站,不是什么钓鱼网站.

所以 CA 就作为了浏览器和网站之间的公证人,让双方知道他就是真实的他,不是伪装者.

证书链

由于互联网上有那么多的网站,绝大多数网站的证书不是由根 CA 直接签发的,而是由中间 CA 签发的,但是浏览器和操作系统只默认信任根 CA 的证书.

为什么要这么做呢?根 CA 证书不能频繁签发,通常离线保存,为了避免安全风险,所以通过中间 CA 作为代理向下签发.于是证书链应运而生.

访问网站时浏览器会:

  • 拿到网站的证书链
  • 根据证书链向上查询,如果可以查到根 CA ,就证明网站可信.

我们后面的过程直接简化掉了这个证书链的过程,大家注意.

4

密钥与加密

可以发现,证书就是我们的身份凭证,那么实际工作中,证书的内容是什么呢? 有了身份凭证就可以做到安全通信了吗?

很明显不够,在庞大的网络线路上,我们还需要对我们的请求进行加密,那么用什么加密呢? 自然是密钥.

公钥与私钥

  • 公钥:可公开,用于加密数据or验证签名,加密后的数据只能用对应的私钥解密
  • 私钥:不可公开,用于解密数据or创建签名;经其签名后的数据,可用公钥验证真实性

对称交换与非对称交换

密钥的概念中有对称交换与非对称交换,这里我们略微介绍一下:

  • 对称交换:双方基于同一个密钥进行通信(加密解密数据)
  • 非对称交换:双方各自持有一对公钥与私钥,发送方使用接收方的公钥加密数据,接收方用自己的私钥解密(正如上面所说)

可以发现,对称交换需要双方提前协商用哪个密钥(这称为密钥交换),而在不安全的通信中如何安全地将这个密钥给到双方,是最大的缺点;而非对称加密不需要事先共享密钥,可以在不安全网络中建立安全连接.

但是非对称的速度太慢,所以我们要将二者结合使用,即混合加密:

先用非对称把对称密钥交换给双方(密钥交换),然后双方基于这个对称密钥进行通信.做到了两全其美.

但是为什么钥先用非对称加密来进行密钥交换呢?具体见下方案例.

举例说明密钥交换过程

有了上面这些概念,我们来大致描述一下浏览器如何与网站进行通信,首先我们来说说上面刚提到的密钥交换.

方案一:单纯非对称加密

  • Step1:网站随机生成密钥对 k1 & k2 (k1是公钥,k2是私钥)
  • Step2:网站保留 k2,将 k1 通过明文方式发给浏览器;即使是明文,被偷窥者拿到也不会推算出k2(密码学原理)
  • Step3:浏览器拿到 k1, 随机生成一个对称加密的密钥 k(视作私钥),用 k1 去加密 k,得到 k’;浏览器将 k’发送给网站
    • 注意,此时只有 k2 才能解密经过 k1 加密的数据(见上方概念);所以偷窥者拿到 k’也不能解密出k
  • Step4:网站拿到 k’,用 k2 解密,得到 k,至此双方就可以用 k 来进行数据交换的加密,建立起 SSL 隧道

这个过程看起来严密,但是攻击者(我)可以伪造密钥对——我在第二步时截获 k1,我自己生成一个伪造的密钥对 fk1 & fk2,将 fk1 抢先发给浏览器

  • 浏览器拿到 fk1,以为是网站的 k1, 就用其加密 k,将 k’ 发出去
  • 发出去后,再次被我截获,我拿 fk2 解密 k’,就会得到 k;此时,我再用之前的 k1去加密 k,得到 k’’,将其发给网站
  • 最后网站利用 k2 解密 k’’,发现可以正常解密,以为自己与浏览器已经建立起了加密通道.

总结一下就是攻击者(我)让浏览器以为我是网站,让网站以为我是浏览器.这就是中间人攻击(Man-In-The-Middle attack)

4

方案二:添加CA证书

核心问题在于浏览器和网站不知道发来的公钥是不是对方的,这就需要身份认证,也就是我们之前提到的证书与CA环节,CA扮演公证人. 加上 CA 后,整个环节变为了:

  • Step1:网站从 CA 那里购买证书,生成证书,证书内容包括:网站公钥(私钥网站自己保存),域名,有效期,经过 CA 私钥签名后的数字签名——这是信任链的根源,浏览器内置了受信任的 CA 的公钥.
  • Step2:浏览器访问,网站将此证书先发给浏览器,告诉浏览器"我是我",浏览器会提取证书内容,用内置的 CA 公钥解密数字签名;
    • 如果解密成功,就可以基本确定这是要访问的网站,是真的
    • 如果解密失败,浏览器提示 CA 证书安全警告
    • 同时再检查域名是否一致,这样就完成了身份验证,
  • Step3:浏览器从证书中提取出网站公钥,随机生成对称加密的 k, 拿证书中的网站公钥加密 k,得到k’,将 k’ 发给网站
  • Step4:网站用自己的私钥解密 k’,得到 k,至此,密钥交换完成.

这个过程中,就算攻击者拿到了证书,但是当他伪造密钥对发过来时, 由于攻击者没有 CA 的私钥,无法生存有效的数字签名,浏览器会解密失败,显示“此证书不受信任”

这是 RSA 密钥交换,理论上讲,这个方案无懈可击,但是仍有服务器私钥泄漏的风险.

5

握手过程

说了这么多背景知识,终于来到了 SSL(TLS) 的正题,如何建立这个加密的安全通道.

握手环节发生在浏览器查询网站的源服务器阶段or任何其他使用 HTTPS 的通信过程.(例如 DoH);在通过 TCP 握手打开 TCP 连接(HTTP 使用 TCP 连接)后,发生握手.

RSA 密钥交换下的握手

  • Step1:ClinetHello,该消息包含客户端支持的 TLS版本,支持的密码套件,以及一串称为“客户端随机数(client random)”的随机字节
  • Step2:ServerHello,作为对 client hello 消息的回复,服务器发送一条消息,内含服务器的 SSL 证书,服务器选择的密码套件,以及服务器随机数.
  • Step3:客户端拿到 SSL 证书开始身份验证(上面讨论过)
  • Step4:ClinetKeyExchange: 发送 premaster secret(就是上面的 k’)给服务器
  • Step5:服务器使用私钥解密
  • Step6:双方生成会话密钥(就是上面的 k)
  • Step7:客户端发送 Change Cipher Spec通知,同时发送加密的 Finished 消息验证握手完整性
  • Step8:服务器发送加密的 Finished 消息
  • Step9:至此,已完成了握手,使用 k 进行后续的通信.

一共2-RTT

6

TLS1.3 ECDHE密钥交换

在新版本 TLS1.3 中,不再支持 RSA密钥交换,缩短了握手过程

  • ClinetHello:由于已从 TLS 1.3 中删除了对不安全密码套件的支持,因此可能的密码套件数量大大减少
    • 客户端问候消息还包括将用于计算预主密钥的参数(例如ECDHE)。大体上来说,客户端假设它知道服务器的首选密钥交换方法(由于简化的密码套件列表,它有可能知道)。
    • 这减少了握手的总长度——这是 TLS 1.3 握手与 TLS 1.0、1.1 和 1.2 握手之间的重要区别之一
  • 服务器生成主密钥:此时,服务器已经接收到客户端随机数以及客户端的参数和密码套件。它已经拥有服务器随机数,因为它可以自己生成。因此,服务器可以创建主密钥 k
  • 服务器问候和“完成”:服务器问候包括服务器的证书、数字签名、服务器随机数和选择的密码套件。因为它已经有了主密钥,所以它也发送了一个“完成”消息
  • 最后步骤和客户端“完成”:客户端验证签名和证书,生成主密钥,并发送“完成”消息

缩短到了1-RTT,k是由客户端与服务器各自独立生成的,至于其中的原理,涉及到密码学,还不是鼠鼠我考虑涉及的领域,总之就是 ECDHE 这个算法很牛逼.

7

如何应用 TLS

在这篇文章中,我们建立了 Docker 私有镜像仓库,使用到了 TLS 证书.

在这个过程中, 仓库就相当于是网站服务器, Docker 客户端就相当于是浏览器.

在实现时,我们将 Let’s Encrypt 这个 CA 生成的证书复制给了仓库 registry 容器使用, 每当我们使用 docker 命令例如 docker pull/push myregistry.example.com/image:tag时, Docker Daemon 就会向仓库发起 HTTPS 请求. 仓库会监听 HTTPS 端口(43),响应客户端的请求.

我们拿当时生成证书后产生的结果说明:

Your cert is in: /root/.acme.sh/jimlt.bfsmlt.top_ecc/jimlt.bfsmlt.top.cer
[Fri May  9 09:53:29 AM CST 2025] Your cert key is in: /root/.acme.sh/jimlt.bfsmlt.top_ecc/jimlt.bfsmlt.top.key
[Fri May  9 09:53:29 AM CST 2025] The intermediate CA cert is in: /root/.acme.sh/jimlt.bfsmlt.top_ecc/ca.cer
[Fri May  9 09:53:29 AM CST 2025] And the full-chain cert is in: /root/.acme.sh/jimlt.bfsmlt.top_ecc/fullchain.cer
  • top.cer 是我的站点的证书,即服务器证书,包括域名,公钥,有效期,签发者等信息
  • top.key 是服务器私钥
  • ca.cer 是中间 CA 机构的证书
  • fullchain.cer 是完整的证书链,可以让浏览器从我的网站一路向上追溯到根 CA

应用中遇到的问题

date 如何影响 TLS

ssh 连接中的证书

总结

本文介绍了 HTTPS 中的 SSL,包括非对称加密,密钥交换,证书,CA,握手等概念.

本文的写作动机是在进行相关操作时通常对操作过程的原理不够清楚,导致操作过程中出错也不置可否,所以旨在弄清楚每一个过程中的原理,让自己能够安心操作.(不只是依赖于 AI)

当然,本文对 SSL 的一些细节并没有过于深入,特别是密码学的部分,有兴趣的地方希望大家补充.

这里是LTX,感谢您阅读这篇博客,人生海海,和自己对话,像只蝴蝶纵横四海。

引用