Appearance
🎫 证书是怎么工作的
先想一个生活里的场景:
你去银行柜台取钱。柜员凭什么相信你是你?
靠身份证。而柜员之所以信这张卡片,不是因为它印得好看,是因为上面有公安机关的防伪印章——柜员不认识你,但他认公安机关。
HTTPS 证书,就是网站的身份证。这篇文章从头到尾只用这一个比方,把它讲透。
读完你会知道:
- 证书到底证明了什么,为什么说它根本不负责加密
- 信任链为什么是三层,
fullchain.pem和cert.pem差在哪(最高频的坑) .crt.cer.pem.key.p12这堆后缀怎么分——以及为什么它们其实没区别- 申请证书时那三种验证方式该选哪个
- 私钥泄露了到底能不能补救(剧透:基本不能)
这篇是前置阅读
如果你要配的是 Cloudflare 那条链路,读完这篇再去看 👉 Cloudflare 回源 SSL 与源站证书,那边讲的是这些证书在真实链路里怎么摆。
一、证书就是网站的身份证
一句话定义:
证书 = 公钥 + 身份信息 + CA 的数字签名
对着身份证看一遍,就全明白了:
| 身份证上的 | 证书里的 | 作用 |
|---|---|---|
| 你的照片 | 公钥 | 用来核对"是不是本人" |
| 姓名、住址 | 域名(example.com) | 你是谁 |
| 公安机关的防伪印章 | CA 的数字签名 | 凭什么信这张卡 |
| 有效期 2020–2040 | 有效期 | 过期作废 |
而 CA(Certificate Authority,证书颁发机构)就是发身份证的公安局。它干的活只有一件:核实你确实是你,然后盖个章。
最容易搞反的一点
证书解决的是身份,不是加密
很多人以为"装了证书才能加密"。反了。
没有证书,HTTPS 照样能加密。问题在于你不知道对面是谁。
打个比方:你接到一个电话,信号非常清晰,没有任何人能窃听(这就是加密)。但对面自称是公安局——你怎么知道他不是骗子?
电信诈骗成立的关键从来不是"通话被监听",而是"你信错了人"。证书就是用来防这个的。
底下的三块积木
不用懂数学,知道它们各自像什么就够了:
| 积木 | 生活里的对应 | 一句话 |
|---|---|---|
| 哈希 | 文件的"指纹" | 合同改一个字,指纹完全不一样 |
| 非对称加密 | 一把公开的锁 + 一把私藏的钥匙 | 锁能随便发,钥匙只有你有 |
| 数字签名 | 你的亲笔签名 | 只有你签得出,但谁都能核对 |
加密和签名,方向是反的
加密像小区门口的快递柜:谁都能往里放件(用公钥加密),只有你能取出来(私钥解密)。保护的是内容。
签名像在合同上按手印:只有你按得出来(私钥签名),但谁都能拿去比对(公钥验证)。证明的是来源。
证书用的是签名。 CA 做的事就是:在"这个域名 + 这把公钥"这句话下面,按了个只有它按得出来的手印。
二、身份证上都印了什么
证书的标准格式叫 X.509。用 openssl x509 -text 打开一张,真正要看的就这几栏:
| 字段 | 相当于身份证上的 | 踩坑点 |
|---|---|---|
Subject | 姓名 | 现在浏览器已经不看这栏了 |
Subject Alternative Name | 姓名 + 所有曾用名 | 真正生效的是这栏,漏一个域名就报错 |
Issuer | 签发机关(XX 分局) | 要和上级对得上 |
Validity | 有效期起止 | 服务器时间不对也会失败 |
Public Key | 照片 | RSA 2048 或 EC P-256 |
Basic Constraints | 是不是"能给别人发证的机关" | 普通证书这栏必须是 FALSE |
Key Usage | 这张证能办什么业务 | 缺 serverAuth 就不能用于 HTTPS |
Signature | 防伪印章本身 | 验证时验的就是它 |
CN 是历史遗留,现在只认 SAN
早年靠 Subject 里的 CN 那栏匹配域名。后来一张证书要覆盖多个域名,就加了 SAN(Subject Alternative Name),相当于身份证背面附一页"曾用名清单"。
从 2017 年起 Chrome 彻底忽略 CN,只翻那页清单。所以哪怕 CN 写对了,清单里漏了域名照样红页。
证书是公开的,私钥不是
这两样东西经常被搞混,但性质天差地别:
证书(.pem / .crt) | 私钥(.key) | |
|---|---|---|
| 好比 | 身份证复印件 | 你本人 |
| 能给别人吗 | 能,它本来就全球公开 | 绝对不能 |
| 泄露了会怎样 | 没事 | 整套作废,重来 |
证书里没有私钥
证书本来就公开躺在 CT 日志里,任何人都能查到你签过哪些证书。发到网上都没事。
私钥是另一个文件,躺在你服务器上,权限必须是 600。
分不清这两个,就会出现"把 .key 发到群里"这种事故。
三、信任链:为什么要三层
浏览器不认识你的网站,就像银行柜员不认识你。那它凭什么信?
因为它认识给你发证的那个机关。
- 根证书:自己给自己盖章(因为它就是最高权威),出厂时就装在你手机和电脑里了
- 中间证书:CA 天天干活用的那一层
- 叶子证书:你的域名证书
为什么公安部不直接给你发证
因为最高权威的那枚印章太重要了,得锁在保险柜里离线保管。一旦泄露,全世界的手机电脑都得更新一遍才能撤销它——现实中根本做不到。
所以设计成:根只授权中间,中间天天在线发证。中间那层出事,吊销那一张就完了,根安然无恙。
fullchain 和 cert 差在哪 ⭐
这是配置里最高频的坑,也是这篇文章最有用的一节。
回到柜台:你递过去一张身份证,但柜员只认识公安部,不认识你家那个分局。所以你还得把"公安部授权此分局"的那封介绍信一起递上去。
Let's Encrypt 给你四个文件,就是这个意思:
| 文件 | 里面装的 | 相当于 |
|---|---|---|
cert.pem | 只有你的证书 | ❌ 只递身份证,柜员看不懂签发机关 |
chain.pem | 只有中间证书 | 只有那封介绍信 |
fullchain.pem | 你的证书 + 介绍信 | ✅ Nginx 填这个 |
privkey.pem | 私钥 | 你本人,永远不递出去 |
nginx
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;为什么"我用浏览器测着好好的"
Chrome 这类浏览器是个特别热心的柜员:你没带介绍信,它会自己打电话去分局核实(读证书里的 AIA 字段主动抓取)。所以你少配了中间证书,浏览器看着一切正常。
但 curl、Java 客户端、Go、老安卓、各种 SDK 是不会打这个电话的,它们直接把你打发走:
unable to get local issuer certificate结论:永远用 fullchain.pem。 别拿浏览器当验收标准——它太好说话了。
四、验证的时候到底在查什么
柜员接过证件后,会按顺序核对:
| 步骤 | 柜台上 | 技术上 |
|---|---|---|
| 1 | 印章是真的吗 | 用上级公钥逐级验签 |
| 2 | 这个机关我认吗 | 链条尽头要能落到本机信任库里 |
| 3 | 过期了吗 | 比对 notBefore / notAfter |
| 4 | 名字对得上吗 | SAN 里有没有当前域名 |
| 5 | 挂失了吗 | 查 OCSP(见第八节) |
| 6 | 有没有登记备案 | 查 CT 透明日志(Chrome 强制) |
任何一步没过 → 红色警告页。
顺便说个反直觉的:验完身份,双方还会另外对暗号
证书验过了,只说明"对面确实是 example.com"。真正用来加密聊天内容的密钥,是握手时临时协商出来的另一套,跟证书里那把公钥没关系。
好比:你验完对方的工作证,进了会议室,然后你们当场约定了一套只有今天有效的暗号,聊完就作废。
这就是前向保密——哪怕多年后服务器私钥泄露了,攻击者当年录下的那段对话,照样解不开。
五、证书的种类
按"查得多严"分
| 类型 | 查什么 | 好比 |
|---|---|---|
| DV | 只确认你能进这个门 | 你有这套房的钥匙 |
| OV | 额外核实公司实体 | 还查了你的房产证 |
| EV | 最严格的人工核验 | 还上门 + 查户口 |
Let's Encrypt 属于 DV,免费、几秒钟签发。
别为 EV 花钱
三者的加密强度一模一样——门锁质量完全相同,区别只在办证时查得多严。
而且浏览器早就取消了 EV 的绿色地址栏(Chrome、Firefox 2019 年双双下线),用户根本看不出区别。EV 的商业价值基本归零了。
按"能罩多大范围"分
| 类型 | 覆盖 | 好比 |
|---|---|---|
| 单域名 | example.com | 一张门禁卡开一个门 |
| SAN 多域名 | 一张证书塞多个域名 | 一张卡开指定的几个门 |
| 通配符 | *.example.com | 一张卡开某一层的所有门 |
通配符只管一层,别想当然
*.example.com 能开 www.example.com、api.example.com——同一层的门。
但它开不了 a.b.example.com(又深了一层),也开不了裸域 example.com(那是楼本身,不是这层的门)。
所以标准做法是:SAN 里同时写 example.com 和 *.example.com 两条。
六、文件格式:最劝退的部分
| 格式 | 本质 | 长什么样 | 常见后缀 |
|---|---|---|---|
| PEM | 文本 | -----BEGIN CERTIFICATE----- | .pem .crt .cer .key |
| DER | 二进制 | 记事本打开是乱码 | .der .cer |
| PKCS#12 | 二进制打包,带密码 | 证书 + 私钥装一个包 | .p12 .pfx |
| JKS | Java 专用格式 | keytool 管理 | .jks |
| CSR | 文本 | BEGIN CERTIFICATE REQUEST | .csr |
后缀名根本不代表格式
.crt / .cer / .pem 就是个文件名,跟里面装什么没有必然关系。改个后缀照样能用。
好比箱子外面贴的标签——写着"衣服"的箱子里完全可能装着书。Windows 圈习惯贴 .cer,Linux 圈习惯贴 .pem,仅此而已。
要判断就打开看:开头是 -----BEGIN 就是 PEM,一堆乱码就是 DER。
PEM 文件的第一行才是真正的身份证明:
| 开头写着 | 里面是 |
|---|---|
BEGIN CERTIFICATE | 证书 |
BEGIN CERTIFICATE REQUEST | 申请表(CSR) |
BEGIN PRIVATE KEY | 私钥(通用格式) |
BEGIN RSA PRIVATE KEY | 私钥(仅 RSA) |
BEGIN EC PRIVATE KEY | 私钥(椭圆曲线) |
一个 PEM 文件里可以连着放好几段——fullchain.pem 就是"身份证 + 介绍信"两张纸订在一起,顺序不能反:自己的在前,介绍信在后。
七、怎么申请下来的
关键在于:第一步是在你自己电脑上做的,私钥从头到尾没离开过本地。
好比办证时你只交了申请表和照片(CSR 里只有公钥),人(私钥)始终在你自己这。申请表半路被人捡走了也没用——照片人人可见,但没法冒充你。
三种"核实域名"的方式
certbot、acme.sh 这些工具把"核实"这步自动化了,方式有三种:
| 方式 | 怎么证明这域名是你的 | 好比 | 能签通配符 |
|---|---|---|---|
| HTTP-01 | 在网站指定路径放个文件 | 上门核验,你必须在家开门 | ❌ |
| DNS-01 | 加一条 TXT 解析记录 | 去派出所登记,不用在家 | ✅ |
| TLS-ALPN-01 | 走 443 的特殊握手 | 走后门核验 | ❌ |
怎么选:
- 普通网站、80 端口开着 → HTTP-01,最省事
- 要通配符,或者服务器根本不暴露在公网(内网服务、K8s)→ DNS-01,唯一选择
- 80 被占了又不想动 → TLS-ALPN-01
为什么只有 DNS-01 能签通配符
"上门核验"只能证明这一个门是你的;而去派出所登记证明的是整栋楼的产权。
要一张卡开这一层所有的门,光让人上门敲一间屋子的门显然不够。
有效期为什么越来越短
证书有效期一路被压缩:早年 5 年 → 3 年 → 2 年 → 1 年 → Let's Encrypt 的 90 天,行业还在往 47 天推进。
两个原因:
- 万一钥匙丢了,能被冒用的时间更短(下一节会讲,"挂失"这套基本是坏的)
- 逼你自动化——一年一次的事人会忘,一个半月一次的事只能写脚本
八、"挂失"这套机制,基本是坏的
私钥泄露了怎么办?理论上通知 CA 把证书吊销掉——就像身份证丢了去挂失。
现实是这套机制几乎不起作用:
| 机制 | 相当于 | 为什么不好使 |
|---|---|---|
| CRL | 柜台后面贴着一沓挂失名单 | 名单好几 MB,柜员根本不翻 |
| OCSP | 柜员打电话去派出所问 | 慢,而且暴露了你在哪办业务 |
| OCSP Stapling | 你自己带一张昨天开的"此证有效"证明 | ✅ 又快又不泄露隐私 |
OCSP 的致命伤:电话打不通就放行
浏览器查挂失状态时,如果超时或失败,默认直接放行。
因为反过来做的话,CA 的服务器一抖动,全网站点集体打不开——没有哪个浏览器厂商敢这么干。
结果就是:攻击者只要把这通电话掐掉,挂失检查就等于不存在。
Stapling 是让服务器自己定期去开好证明、握手时一并递上:
nginx
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;正因为挂失靠不住,行业真正的解法是让证件本身短命。 这就是 90 天的根本原因——与其指望挂失系统,不如让身份证三个月就自动作废。
九、自己发证:内网、工牌和对暗号
自签名证书
自己在家用打印机做了张身份证。你自己认,银行不认。
技术上就是 Issuer 和 Subject 是同一个——自己给自己盖章。浏览器必然报警,这是正常的,不是你配错了。
只适合本地开发和纯内网。
私有 CA
公司自己发的工牌。 你搞一张自己的根证书,手动导入到公司所有机器的信任库里,然后用它给内部服务发证。
公司里畅通无阻,出了公司一文不值。
内网服务、K8s 组件间通信走的都是这套。Cloudflare 的 Origin CA 本质上也是私有工牌——只有 Cloudflare 认它。
mTLS 双向认证
平时是单向的:你验银行的身份,银行不验你的证件(靠密码认人)。
mTLS 是双向的——两边都要出示证件,像特工接头对暗号:
nginx
ssl_client_certificate /etc/nginx/ca.crt;
ssl_verify_client on;用在 API 网关、服务网格(Istio)、企业 VPN:证书本身就是通行证,拿不出来连门都进不了。
十、常见报错速查
| 报错 | 真实原因 | 怎么修 |
|---|---|---|
unable to get local issuer certificate | 介绍信没递(缺中间证书) | 换成 fullchain.pem |
NET::ERR_CERT_AUTHORITY_INVALID | 自制证件 / 工牌没导入 | 导入根证书,或换公共 CA |
NET::ERR_CERT_COMMON_NAME_INVALID | 名字对不上(SAN 里没这域名) | 重签,把域名加进 SAN |
certificate has expired | 过期了,或服务器时间不对 | 先 date 看一眼再说 |
key values mismatch | 证件和本人不是一个 | 见下面的 modulus 比对 |
SSL_ERROR_NO_CYPHER_OVERLAP | 双方语言不通(协议/套件) | 老客户端 vs 只开 TLS 1.3 |
| Cloudflare 526 | 源站证书没通过校验 | 见 Cloudflare 那篇 |
十一、openssl 排错命令
摊开看一张证书都写了什么:
bash
openssl x509 -in fullchain.pem -noout -text只看有效期和域名清单(最常用):
bash
openssl x509 -in cert.pem -noout -dates -ext subjectAltName远程查一个站点,-showcerts 能看出介绍信递没递:
bash
openssl s_client -connect example.com:443 -servername example.com -showcerts确认证书和私钥是不是一对——下面两条命令输出的 md5 一样才对:
bash
openssl x509 -noout -modulus -in cert.pem | openssl md5bash
openssl rsa -noout -modulus -in privkey.pem | openssl md5看看申请表里填了什么:
bash
openssl req -in request.csr -noout -text -verifyPEM 转 PKCS#12(给 Java / Windows 用):
bash
openssl pkcs12 -export -out bundle.pfx -inkey privkey.pem -in cert.pem -certfile chain.pemDER 转 PEM(拿到乱码文件时):
bash
openssl x509 -inform DER -in cert.der -out cert.pem-servername 千万别漏
现在一个 IP 上跑几十个网站是常态。好比一栋写字楼共用一个门牌号,你进门得先跟前台说"我找 A 公司"(这就是 SNI),前台才知道该给你哪家的接待。
s_client 不加 -servername 就等于闷头往里走,前台默认把你领到物业办公室——然后你对着一张不相干的证书排查半天。
十二、只记三句话
总结
- 证书是身份证,不是锁。私钥才是命根子——证书随便公开,
.key泄露就得全部重来 - 递证件要连介绍信一起递,用
fullchain.pem——浏览器会热心地帮你补,curl 和 Java 不会 - 挂失机制靠不住,所以证件越来越短命——自动续期不是可选项,是必需品
想看这些证书在真实链路里怎么摆(Cloudflare 回源、Origin CA、Let's Encrypt DNS-01 实操),见 👉 Cloudflare 回源 SSL 与源站证书