3113 字
约 10 分钟
20
S02-A07 · TLS 终止位置:代理链路上的信任边界

"证书到底配在哪一层"这个问题,通常是在排查"证书不属于这个域名""应用拿到的协议是 http""跳转后掉回明文"时才被提出来的。三个症状同一个根源:TLS 在某处被解开,却没人记录过它在哪被解开。终止位置一定,后面每一跳的信道性质、可观测信息、证书续期责任就都跟着固定。这篇只谈位置的判据。


1. 先把"证书配在哪"拆成三个问题

问题 答案决定什么 常见错答
客户端看到的证书由谁签发 信任链、客户端兼容性 "反代有证书就够了",忽略内层也在发证
走到应用时是明文还是 TLS 内网是否需要加密、能否被旁路嗅探 "内网安全",于是全链路明文
应用看到的协议与客户端 IP 从哪来 生成链接、限流、审计的准确性 直接信任 Host 与 X-Forwarded-*

三个问题必须同时回答。只答第一个,就得到"外部 HTTPS、内部全明文、应用以为自己在 HTTP 上跑"——最常见也最难查。

2. 四个终止位置与各自的信任边界

位置 明文暴露段 私钥放在哪 运维代价 适合
边缘 CDN 源站回源段(可配 TLS) CDN 托管或源站持有 最低,证书与续期被托管 公网站点、静态为主
入口网关/反代 网关到应用 网关节点 中等,网关升级即全局风险 单体或少量服务
应用进程内 无(进程内解密) 每个应用实例 高,证书分发到所有副本 服务少、要求端到端
全程透传(L4) 无 后端 中,L4 不解密则功能受限 需要端到端、或不可解密

四种常被混用:CDN 终止 + 回源再建 TLS + 网关终止 + 内网明文。审计要的是这份逐段清单,不是"我们上了 HTTPS"。

3. 终止越靠前,后面是否明文——安全与运维的同一个决策

这不是两个议题。把终止点前移,同时得到三件东西和失去三件东西:

前移得到 前移失去
证书集中管理,续期只做一次 内网段明文,横向移动可直接嗅探
后端不需要处理握手,CPU 压力集中 应用无法直接看到真实客户端证书
统一 WAF、限流、日志入口 单一节点成为全局单点与性能瓶颈

反向移动则相反:内网每段都要有自己的证书与轮换,换来"任何一跳被拿下都不等于全链路明文"。

判据是内网段的信任等级是否一致。同机、同 VPC、无第三方运维,明文可接受;跨机房、跨云、跨承接方,明文段就是没有名字的信任漏洞。

4. mTLS:适用面窄,运维成本高

场景 mTLS 是否合适 原因
服务网格内部身份 合适 有统一 CA 与自动轮换,证书生命周期被平台接管
第三方 B2B 对接 合适 双方可预先交换 CA,连接数有限
移动端/浏览器直连 不合适 客户端证书分发与吊销成本极高
临时脚本调用内部 API 不合适 证书分发比 token 更难回收

mTLS 的成本不在握手,在证书生命周期:签发、轮换、吊销、过期告警都要有归属人。没有自动轮换的 mTLS,半年后必有一次"凌晨全部连接失败"。

# 网格侧的典型配置形态(字段名按所用实现核对)
mtls:
  mode: STRICT            # PERMISSIVE 只应用于迁移窗口
  ca:
    rotateBefore: 720h    # 早于过期前轮换,留出重试窗口
  workloadSelector:
    app: payments

5. HTTP/2 与 HTTP/3 对拓扑的约束

层 能否协商 h2 关键约束
客户端到 CDN 通常可以 CDN 支持 ALPN 即可
CDN 到源站 常被降级为 h1.1 需显式开启回源 HTTP/2,且源站要支持
网关到应用 取决于网关与应用的协议 明文 h2c 支持不一致,多数走 h1.1
端到端 h3 基本不成立 h3 依赖 QUIC,通常只在最后一跳到边缘之间

结论:边缘支持不等于全链支持。一次请求可能第一段 h3、第二段 h1.1、第三段 h2c,多路复用收益只在前两段成立。

curl -sI --http2 https://TARGET/ | head -3
# 逐层验证:对 CDN、源站、内网入口各查一次 ALPN 与协议版本
openssl s_client -connect TARGET:443 -alpn h2 </dev/null 2>/dev/null | grep ALPN

6. X-Forwarded-* 的信任问题

头 谁应该写 应用必须校验什么 不校验的后果
X-Forwarded-For 最外层可信代理追加 只取最右侧可信跳之后的第一个 客户端自带该头即可伪造来源 IP
X-Forwarded-Proto 终止 TLS 的那一层 只在该层覆盖后信任 生成 http:// 链接、Cookie 缺 Secure
X-Forwarded-Host 同上 与 Host 白名单比对 密码重置链接指向攻击者域名
Forwarded(RFC 7239) 同上 同上,注意多值解析 同上

伪造的根源永远是入口没有剥离客户端自带的同名头。正确顺序是:入口代理先清空再写入,应用只信任来自已知代理网段的值。

# 入口层:先清空,再按实际连接写入
proxy_set_header X-Forwarded-For "";
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host  $host;

跨两层时 $remote_addr 已是上一层代理地址,需 real_ip 配合可信网段还原;漏了这一步,日志全是代理 IP,风控与限流一起失效。

7. 重定向与 HSTS 在多层代理下的坑

现象 成因 处理
无限重定向 应用看到 http,跳 https;边缘看到 https 又跳回 应用层信任 X-Forwarded-Proto,或只在一层做跳转
跳转后端口/协议丢失 应用拼接绝对 URL 时用了内部地址 用相对跳转,或配置外部基址
HSTS 首次不生效 首个响应是明文跳转 跳转响应也要带 Strict-Transport-Security
内网 IP 被 HSTS 锁死 浏览器对 IP 也记录 只对确定域名下发,max-age 先小后大
includeSubDomains 打挂旧子域 旧子域只有 HTTP 先盘点全部子域再开
add_header Strict-Transport-Security "max-age=300" always;   # 灰度期用短值
# 稳定后再升到 31536000,并在确认全部子域支持 HTTPS 后才加 includeSubDomains

HSTS 单向:下发长 max-age 后,客户端在到期前不会再用 HTTP。所以"先短后长"是唯一稳妥路径。

8. 证书管理:三种形态的取舍

形态 覆盖范围 风险 适用
单域名证书 一个 FQDN 数量爆炸,续期漏一个就断 域名极少
多域名(SAN) 一组 FQDN 任一新域名要重签所有节点 域名固定且集中
通配符 一级子域全部 一处泄露即全部可仿冒 子域动态、无法枚举

通配符不覆盖 a.b.example.com(多级子域),也不覆盖裸域,这两点是最常见的证书不匹配来源。

# 自动续期后的验收:不只看退出码,要看实际生效的证书与剩余天数
openssl s_client -connect TARGET:443 -servername TARGET </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -enddate

私钥位置比签发方式更重要:能读到私钥就能冒充该域名。判据是"私钥主机的管理员数量",不是文件权限 600。

9. 会话复用与 TLS 1.3 的 0-RTT

机制 省下的往返 风险
Session ID / Session Ticket 完整握手降为 1-RTT 或 0-RTT Ticket 密钥轮换不当会削弱前向保密
TLS 1.3 0-RTT 首个请求即可带数据 可重放:早期数据可被攻击者截获重发
连接复用(keep-alive) 完全省掉握手 长连接把证书轮换的生效时间推迟到下次建连

0-RTT 可重放,意味着非幂等请求都不该走 0-RTT——在终止层限制其范围,而不是在应用层做去重兜底。

10. 加解密对延迟的影响量级

项 典型量级 说明
TLS 1.2 完整握手 约 2 RTT 含证书链传输与验证
TLS 1.3 完整握手 约 1 RTT 证书链仍要传
会话恢复 0–1 RTT 取决于票据命中
单请求加解密开销 亚毫秒到毫秒级 与报文大小、密码套件相关

决定体验的不是单次加解密,是握手次数:终止越靠前,后端越容易复用长连接,握手总数更少;后移到每个服务,握手数随服务数增长。

11. 与 SSO、可观测、合规的叠加

关注点 终止在前(CDN/网关) 终止在后(应用/透传)
单点登录 可在网关做统一重定向与 Cookie 域 每个应用各做一套
客户端证书认证 网关可见证书主体,可映射为身份 应用自行解析,标准不统一
可观测 能看到完整 URL、头、状态码 只能看到 SNI、IP、流量特征
合规(数据不出域) 解密点集中在少数节点,好审计 解密分散,审计面变大

合规把拓扑推向两个相反方向:"中间节点不得解密"与"必须能审计内容"无法同时满足,只能分区——敏感流量透传,普通流量在网关终止。

12. 排错

现象 原因 处理
浏览器报证书不属于该域名 某一层仍在用旧证书或默认证书 逐层用 openssl s_client -servername 查实际证书
应用生成的所有链接都是 http 未信任 X-Forwarded-Proto 在终止层覆盖该头,应用侧收敛信任来源
客户端 IP 全是同一个地址 未配置可信网段还原 配 real_ip 或让入口写 X-Forwarded-For
部分客户端握手失败 协议版本/套件过窄,或证书链缺中间证书 补齐 fullchain,保留 TLS 1.2 兼容
轮换证书后未生效 连接复用让旧会话继续 主动断开长连接或缩短会话票据有效期

13. 边界

场景 更合适的做法 理由
纯内网、单机部署 直接用自签证书或明文 没有中间人面,拓扑复杂度换不到收益
已有服务网格统一接管 交给网格的 mTLS 策略 自建设计会与平台策略冲突
强合规不可解密 全程 L4 透传,牺牲可观测 用流量特征与端侧日志补足

14. 自测

  1. "证书配在哪一层"背后其实要同时回答哪三个问题?
  2. 把终止点从应用前移到 CDN,内网段的性质发生了什么变化?
  3. 边缘支持 HTTP/3,是否意味着端到端都是 h3?为什么?
  4. 客户端自带的 X-Forwarded-For 为什么能生效,入口该怎么处理?
  5. HSTS 为什么必须"先短 max-age 后长"?
  6. 什么情况下透传(不解密)反而是更正确的选择?
S02-A07 · TLS 终止位置:代理链路上的信任边界
https://www.clxhxhhr.top/posts/6201/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。