相关原理

TLS 与证书

TLS 如何证明服务器身份、证书的 SAN 匹配规则、TLS 1.3 的握手流程与双向认证(mTLS)
本文只讲原理,不涉及配置。启用 HTTPS 请见 AutoTLS;密码套件、密钥交换等算法细节见密码学基础。

1. 加密与身份

TLS 同时解决两件事:

  • 加密:链路被截获也读不出内容,被篡改也能发现
  • 身份:向访客证明「连接的确实是 example.com」,而不是冒充它的中间设备

两者是分开的。任何一对公私钥都能协商出加密通道,自签证书同样可以;证书只负责身份。所以「自签不安全」的准确含义是「没人能确认它是谁」,而不是「流量没有加密」。

2. 证书

证书是一份由 CA 签名的文件,核心内容如下:

内容作用
域名这张证书代表哪些名字,格式见 2.1
公钥与私钥配对,用于握手
有效期到期即失效,需要重新签发
签发者与签名让客户端能从内置的根证书验到它

私钥不在证书里,与证书分开保存。谁终止 TLS,私钥就在谁手里:证书可以公开,私钥泄露等于身份被冒用。

验证是一条链:客户端从操作系统或浏览器内置的根证书出发,用签发者的公钥逐级验签,直到这张证书。链上少一环——例如只部署了域名证书、漏掉中间证书——验证就不成立,部分客户端会直接报证书无效。

2.1 Subject Alternative Name

证书里列出域名的字段是 Subject Alternative Name(SAN)。客户端只看这一项,CN 已被忽略,只填 CN 的证书在现代客户端上不会被接受。

匹配规则:

规则说明
逐字匹配访问的域名要与 SAN 中某一项完全一致(大小写不敏感)
通配符只能位于最左一个标签,且只覆盖一级:*.example.com 含 a.example.com,不含 example.com,也不含 a.b.example.com
多个名字一个 SAN 可以列出多个域名,一张证书服务多个站点
IP 地址IP 也能写进 SAN,用 IP 直连时客户端校验的是这一项
非 ASCII证书里写 punycode 形式(xn-- 开头)

名字写死在证书里,所以换域名就意味着重新签发;用 IP 访问只签了域名的证书,同样校验不过。

3. 握手

以 TLS 1.3 为例:

  1. ClientHello:访客报出支持的版本与密码套件、一个随机数(client_random),并附上自己的临时公钥;SNI 与 ALPN 也在这里。整条消息都是明文
  2. ServerHello:服务器选定一套密码套件,回一个随机数(server_random)和自己的临时公钥。此刻双方的共享秘密已经成立,握手密钥随之导出
  3. 此后全部加密:EncryptedExtensions(ALPN 结果等)→ Certificate(证书链)→ CertificateVerify(用证书私钥对握手记录签名)→ Finished
  4. 客户端回 Finished:校验通过后才开始发送应用数据
  5. 应用数据:用协商出的会话密钥对称加密

几点值得注意:

  • 证书链在 1.3 里是密钥成立之后才发出,且已经加密;TLS 1.2 则是证书与 ServerKeyExchange 同一趟明文送出
  • 明文只剩第一条消息,其中的 SNI 正是节点能在不解密的情况下按域名选路的依据,见 HTTP 虚拟主机
  • CertificateVerify 用私钥签名,把证书与本次握手绑定在一起;只看证书链验不出私钥在谁手里
  • 默认一次往返完成握手;会话恢复可以 0-RTT,代价是 0-RTT 数据有重放风险

4. 双向认证(mTLS)

默认流程里只有服务器出示证书,访客验证它,这叫单向认证。**双向认证(mTLS)**要求访客也出示证书,服务器同样验它的签名链,并确认它由自己信任的 CA 签发。

在 TLS 1.3 里,服务器发出 CertificateRequest,客户端回应自己的 Certificate 与 CertificateVerify,握手其余部分不变;TLS 1.2 的 CertificateRequest 位置靠前一些,本质相同。

两边的证书通常来自不同地方:服务器证书要能被不特定的客户端信任,由公开 CA 签发;客户端证书一般由自己架的 CA 签发,只把该 CA 的证书交给服务器校验即可。

5. 签发

签发是 CA 用自己的私钥为证书签名。公开 CA 不能凭空相信一个域名,签发前要求申请人先证明自己控制着它,证明方式有几种,区别只在于把证明放在哪里,详见 Let's Encrypt 的挑战类型说明。自签不需要证明,代价是没有任何客户端会信任它,除非手动把这张证书或自建的根证书导入信任列表,所以只适合自用测试。

Lolia 的 AutoTLS 用的是 Let's Encrypt 的 TLS-ALPN-01,并且在 frpc 本地完成签发与续期:验证流量先到达节点,再按域名交给 frpc。

6. 结论

  • 加密与身份是两件事,自签能加密但证明不了身份
  • 客户端只认 SAN 与信任链,名字对不上或链断了都视为无效
  • TLS 1.3 先用临时公钥成立密钥,证书在加密之后才送达
  • 证书与私钥成对,谁终止 TLS 谁持有私钥
  • 签发的是域名而不是机器,域名变了就要重签
  • 双向认证让访客也出示证书,但它只证明身份,授权仍在应用层
  • 签发发生在本地,验证流量要能经节点到达 frpc