bigywater.tech
微服务 · 34

TLS 终止:证书链配置、握手耗时,以及到上游是明文还是重新加密

网关做 TLS 终止要把证书链配成什么样?RSA 和 ECDSA 的握手差多少?会话复用有多大帮助?到上游是明文还是重新加密,代价和安全性怎么样?这篇用自己签的证书链和 nginx 1.31.6 量出来。

unable to get local issuer certificate
只配叶子证书时 client 的校验错误;配成“叶子 + 中间 CA”才通过
4.14 ms 对 0.88 ms
RSA 4096 与 ECDSA P-256 叶子证书的 TCP + TLS 1.3 握手耗时中位数
verify off
nginx 的 proxy_ssl_verify 默认是 off:上游证书链不完整也照常放行,打开后才返回 502

证书链

实测 · 本机执行输出
  ssl_certificate       | client(只信根 CA)的结果                           | nginx 发出的证书数
  ----------------------+---------------------------------------------+-------------
  只有叶子证书                | 校验失败:unable to get local issuer certificate | 1 张         
  叶子 + 中间 CA(fullchain) | 握手成功,校验通过                                   | 2 张         
  叶子证书不是根 CA 直接签的,client 需要中间 CA 才能一路验证到自己信任的根;服务端不发中间证书,有的 client 会自己去下载(AIA),这里的 Python 不会,所以失败。根 CA 一般不需要发,client 本来就有

叶子证书之外要把中间 CA 一起发出去,client 才能验证到根。

握手耗时与会话复用

实测 · 本机执行输出
  叶子证书    | 服务端允许的版本 | 实际协商    | 握手耗时中位数(TCP + TLS) | p99    
  --------+----------+---------+--------------------+--------
  ec256   | TLSv1.2  | TLSv1.2 | 0.78 ms            | 2.19 ms
  ec256   | TLSv1.3  | TLSv1.3 | 0.88 ms            | 1.52 ms
  rsa2048 | TLSv1.2  | TLSv1.2 | 1.23 ms            | 2.54 ms
  rsa2048 | TLSv1.3  | TLSv1.3 | 1.36 ms            | 2.76 ms
  rsa4096 | TLSv1.2  | TLSv1.2 | 4.25 ms            | 6.68 ms
  rsa4096 | TLSv1.3  | TLSv1.3 | 4.14 ms            | 7.42 ms
  配置(TLS 1.3 默认,RSA 2048)          | 带着上次的会话重连,被复用的次数 | 复用的握手中位数 | 没复用的握手中位数
  ---------------------------------+------------------+----------+----------
  无会话缓存(ssl_session_cache off)     | 0 / 100          | -        | 1.35 ms  
  shared 会话缓存 + session tickets 默认 | 100 / 100        | 0.68 ms  | -        

密钥类型的影响大于 TLS 版本;会话复用把握手耗时降一半。

到上游重新加密与证书校验

实测 · 本机执行输出
  到上游的方式                                            | 延迟中位数   | p99     | 状态码       
  --------------------------------------------------+---------+---------+-----------
  proxy_pass http://(明文)                            | 0.15 ms | 0.48 ms | {200: 500}
  proxy_pass https://,默认                            | 0.15 ms | 0.47 ms | {200: 500}
  https:// + Connection: close(每个请求新建 TLS 连接)       | 1.53 ms | 2.93 ms | {200: 500}
  https:// + Connection: close + 会话复用               | 0.74 ms | 1.75 ms | {200: 500}
  proxy_pass http:// + Connection: close(明文也每次新建连接) | 0.27 ms | 0.66 ms | {200: 500}
  proxy_pass https:// + upstream keepalive 16       | 0.15 ms | 0.46 ms | {200: 500}
  https:// + proxy_ssl_verify on(信任根 CA)            | 0.15 ms | 0.47 ms | {200: 500}
  上游证书的校验:默认的 proxy_ssl_verify 是 off,nginx 不检查上游证书是否可信、名字是否对得上;下面让上游用一张叶子证书(没有发中间 CA),分别在 verify off / on 下请求
  配置                       | 状态码 | error.log                                                                                                                         
  -------------------------+-----+-----------------------------------------------------------------------------------------------------------------------------------
  proxy_ssl_verify off(默认) | 200 | (没有错误)                                                                                                                            
  proxy_ssl_verify on      | 502 | 296#0: *2 upstream SSL certificate verify error: (21:unable to verify the first certificate) while SSL handshaking to upstream, cl

连接被复用时几乎没有额外延迟,新建连接时每次多一次握手;默认不校验上游证书,重新加密不等于认证。

分步演示

TLS 终止
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.8 / Go / nginx / Envoy / etcd / Consul / Nacos / OpenTelemetry / Prometheus(按各篇注明用到哪些及版本);所有服务都是本机自己起的进程,端口 9150 以上,只监听 127.0.0.1,不连任何外部服务,不碰本机已有的实例;故障用 kill -9 进程、让连接断开或在代码里注入延迟与错误来制造;计时用 time.perf_counter,数字每次运行会有小幅抖动。证书由 cryptography 50.0.2 自己签发(根 CA 和中间 CA 是 ECDSA P-256,叶子证书 RSA 2048 / RSA 4096 / ECDSA P-256,有效期 30 天,带 SKI / AKI / KeyUsage——Python 3.14 的校验默认要求这些扩展);nginx 是 Homebrew 的 1.31.6;client 是 Python ssl,只信任这个根 CA;HTTPS 上游是 Python http.server 套 ssl;握手在本机环回上测,没有网络往返,所以 TLS 1.3 省一个往返的好处在这里体现不出来
    • 没有验证:OCSP stapling;ALPN 与 HTTP/2 的协商;mTLS(见 Mesh 部分);证书过期与轮换;真实网络(RTT)下 TLS 1.2 与 1.3 的握手差别;TLS 1.3 的 0-RTT;cipher suite 的选择对耗时的影响
    京ICP备2026067502号-1京公网安备11010502063487号