ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

TLS 证书固定(Certificate Pinning)配置实践

TLS 证书固定(Certificate Pinning)配置实践 TLS 证书固定Certificate Pinning配置实践一次自签证书排障记录从证书验证失败到pinnedPeerCertSha256说明本文仅用于技术学习与个人合法自建服务如内网穿透、个人网站 HTTPS的排障记录。文中内容是一次真实故障的复盘不是搭建/使用教程配置示例仅用于本人自建环境的故障定位请勿用于任何未授权场景。背景给自建服务配上自签证书后应用默认会拒绝它tls: failed to verify certificate: x509: certificate signed by unknown authority常规的两种处理思路思路做法代价把证书加入系统信任把自签 CA 导入操作系统/浏览器的受信任根证书要动系统信任库且对所有程序生效证书固定本文主题只让应用信任这一张证书的指纹换证书要同步改指纹补一句如果应用是浏览器或系统级应用导入自签 CA 到系统信任库是更省事的做法可以用mkcert生成本地 CA。本次排障的场景是应用配置里自带 TLS 验证逻辑不方便改系统信任库所以才走证书固定这条路。早期这类应用配置里还有个allowInsecure: true跳过证书验证。但在 26.x 内核上这个字段已经被移除了。问题现象在 26.3.27 内核上配置里带allowInsecure会直接导致启动失败Failed to start: main: failed to load config files: [./app-test.json] infra/conf: failed to build stream settings for outbound detour infra/conf: Failed to build TLS config. common/errors: The feature allowInsecure has been removed and migrated to pinnedPeerCertSha256. Please update your config(s) according to release note and documentation.注意这个报错的措辞removed and migrated—— 不是改名是功能被替换。旧allowInsecure: true—— 放弃一切验证信任任何证书新pinnedPeerCertSha256: 指纹—— 只信任指定指纹的那张证书从安全角度这是进步旧方案等于完全裸奔中间人攻击无感新方案至少锁定了具体证书。关键排查过程这个问题的表现具有误导性容易把人带偏现象表面判断实际原因应用握手失败网络问题证书验证失败Test-NetConnection返回True端口没问题确实没问题问题在 TLS 层服务端日志handshake did not complete服务端配置错误应用主动中止了握手服务端日志大量invalid connection被攻击或配置错应用重试导致的噪声另一个教训当所有网络层检查都正常但握手就是失败时要怀疑应用自身的配置有没有真正生效—— 而不是继续往网络方向排查。当时的处理方式服务端生成自签证书sudoopenssl req-x509-nodes-newkeyrsa:2048-days3650\-keyout/etc/ssl/private/selfsigned.key\-out/etc/ssl/certs/selfsigned.crt\-subj/CNyour.domain取出证书的 SHA256 指纹这一步是核心。pinnedPeerCertSha256需要的是证书本身的 SHA256不是公钥的sudoopenssl x509-in/etc/ssl/certs/selfsigned.crt-noout-fingerprint-sha256\|seds/.*//; s/://g|trA-Za-z输出是一串64 位十六进制例如a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2拆解这条命令步骤作用openssl x509 -fingerprint -sha256计算证书指纹sed s/.*//去掉SHA256 Fingerprint前缀sed s/://g去掉冒号分隔符tr A-Z a-z统一转小写应用侧这次故障里改动了什么本次在应用侧实际做的改动仅为复现记录不是操作教程在应用的 TLS 设置区里把原先填的「跳过证书验证」改成填「固定证书」值为上一步得到的 SHA256 指纹保存后重启。注意在 26.x 内核上界面里的「跳过证书验证 (allowInsecure)」开关即使能打开也不生效。真正起作用的是「固定证书」。⚠️ 一个容易踩的坑UI 开关 ≠ 内核支持这是本次排查中最反直觉的一点单独拎出来说。应用配置界面上的「跳过证书验证 (allowInsecure)」开关在 26.x 内核下依然可以打开界面上看不出任何异常。但它不会生效。实测对比同一客户端版本 26.9.9 内核其余配置完全相同应用配置结果只开「跳过证书验证」❌x509: certificate signed by unknown authority只填「固定证书」✅ 连接成功两个都开✅ 连接成功pinnedPeerCertSha256生效失败时的日志[Error] transport/internet: failed to dial to SERVER:443 tls: failed to verify certificate: x509: certificate signed by unknown authority **原因**应用的 UI 保留了旧字段的开关但内核已经移除了这个字段。**UI 的状态不能代表配置的实际内容 —— 开关存在不代表它还有后端支持。** **排查这类问题的原则**不要相信界面显示要看**内核版本**和**实际生效的配置字段**。 这个坑的迷惑性在于**它和其他网络层故障的表现几乎一样**握手失败、延迟 -1很容易让人往网络、防火墙、协议方向排查而真正的病根在客户端内核的版本差异上。 ### 验证 验证 TLS 握手是否正常。这里用 example.com 作为目标**换成任何 HTTPS 站点都可以** —— 这一步检验的是证书链能否验证通过与具体访问哪个站点无关 bash curl -s -o /dev/null \ -w 状态: %{http_code} 耗时: %{time_total}s\n \ --max-time 20 https://example.com返回状态: 200即成功。如果身份验证本身失败用curl直接看证书校验的错误-v会打印完整的握手和证书校验过程curl-v--max-time15https://your.domain# 关键行SSL certificate problem: self-signed certificate版本影响范围版本allowInsecure说明≤ 25.x✅ 支持传统方案26.x❌ 已移除必须改用pinnedPeerCertSha256踩坑点网上大量旧资料仍是allowInsecure写法且不会提示版本差异。如果暂时不想改配置降级到 25.x 也能恢复该字段本次排查中验证过 25.12.8 可用。但长期看应该迁移到证书固定理由见下。为什么这个变更值得拥抱allowInsecurepinnedPeerCertSha256安全模型信任任何证书只信任指定指纹中间人攻击无感知会被拒绝证书轮换无感需要同步更新指纹适用场景临时测试生产环境唯一代价证书更新后必须同步更新客户端的指纹。对自用场景来说这是可接受的。附与证书固定相关的最小配置片段本次故障跟传输层怎么搭没有关系—— 报错发生在证书校验阶段早于任何传输协商。所以下面只留与 TLS 证书直接相关的片段。自签证书在 nginx 上终结 TLS自用场景完整server块server { listen 443 ssl; server_name your.domain; ssl_certificate /etc/ssl/certs/selfsigned.crt; ssl_certificate_key /etc/ssl/private/selfsigned.key; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }其中与本文相关的只有两行ssl_certificate/ssl_certificate_key——客户端要固定的指纹来源就是这两个文件里的证书。自签证书的指纹同样可以直接验证不必连服务端openssl x509-in/etc/ssl/certs/selfsigned.crt-noout-subject-dates-fingerprint-sha256小结26.x 内核用pinnedPeerCertSha256取代了allowInsecure指纹用openssl x509 -fingerprint -sha256计算需去掉冒号并转小写应用侧要填「固定证书」而不是「跳过验证」「跳过证书验证」开关在 26.x 内核上能打开但不生效 —— UI 状态不代表内核支持TLS 层故障在 TCP 层表现正常排查要分层新方案安全性更好值得迁移—环境参考Ubuntu 22.04 / nginx 1.18 / 内核 26.9.9 / Windows 应用 7.24.9
返回列表