Let's Encrypt 的 ACME 协议到底干了什么?用抓包带你看一遍

用过 Let's Encrypt 或 certbot 的人都知道,跑一条命令就能拿到免费的 SSL 证书。但这个过程背后到底发生了什么?CA 怎么确认你拥有这个域名?证书是怎么签发出来的?

这些事情都由一个叫 ACME(Automatic Certificate Management Environment)的协议来完成。RFC 8555 定义了它的全部流程。

我用实际的抓包和请求记录,把整个流程走一遍。

ACME 协议要解决的核心问题

传统的 SSL 证书申请流程是这样的:你去 CA 的网站下单 → 选证书类型 → 提交域名 → 做验证(DNS 或邮箱)→ 等人工审核 → 下载证书文件。整个过程可能要几个小时到几天。

ACME 的目标是把这个流程自动化------让客户端程序(比如 certbot)通过 API 和 CA 交互,自动完成域名验证和证书签发。DV 证书的整个签发过程可以在几分钟内完成,不需要人工介入。

完整流程拆解

第一步:发现(Directory)

客户端先请求 CA 的 Directory URL,获取各个 API 端点的地址。

bash 复制代码
GET https://acme-v02.api.letsencrypt.org/directory

返回一个 JSON,包含了 newNonce、newAccount、newOrder 等端点的 URL。这一步相当于拿到一份 API 目录。

第二步:注册账号(Account)

客户端生成一对 RSA 或 ECDSA 密钥(Account Key),用私钥签名一个注册请求发到 newAccount 端点。

arduino 复制代码
POST /acme/new-acct
{
  "termsOfServiceAgreed": true,
  "contact": ["mailto:admin@example.com"]
}

CA 创建账号,返回一个 Account URL。后续所有请求都用这个 Account Key 签名来做身份认证。

这里有一个安全设计值得注意:ACME 的每个 POST 请求都带一个 nonce(防重放攻击),nonce 从 newNonce 端点获取或从上一个响应的 Replay-Nonce header 里拿。

第三步:下单(Order)

客户端发起一个证书申请,告诉 CA 我要给哪些域名签证书。

sql 复制代码
POST /acme/new-order
{
  "identifiers": [
    {"type": "dns", "value": "example.com"},
    {"type": "dns", "value": "*.example.com"}
  ]
}

CA 返回一个 Order 对象,里面包含了需要完成的 authorizations------每个域名对应一个 authorization,你需要逐个完成验证。

第四步:域名验证(Challenge)

这是整个流程的关键。CA 需要确认你真的控制这个域名。ACME 支持几种验证方式:

HTTP-01 验证: CA 给你一个 token,你需要在 http://yourdomain/.well-known/acme-challenge/{token} 放一个包含特定内容的文件。CA 的服务器会来访问这个 URL,如果能拿到正确内容,验证通过。

bash 复制代码
# CA 要求你在这个路径放文件
http://example.com/.well-known/acme-challenge/abc123...

# 文件内容 = token + "." + Account Key 的 Thumbprint
abc123....xyz789...

DNS-01 验证: 在域名的 DNS 里添加一条 TXT 记录。记录名是 _acme-challenge.yourdomain,值是 CA 给的 token 的 SHA-256 哈希值(Base64URL 编码)。

arduino 复制代码
_acme-challenge.example.com  TXT  "dGVzdC10b2tlbi1oYXNo..."

通配符证书必须用 DNS-01 验证,因为 HTTP-01 无法验证 * 域名的所有权。

验证通过后,客户端通知 CA:

bash 复制代码
POST /acme/challenge/{challenge-id}
{}  // 空 body,表示"我准备好了,你来验证"

CA 验证成功后把 authorization 的状态标记为 valid

第五步:签发证书(Finalize)

所有域名验证通过后,客户端生成一对新的密钥(Certificate Key,和 Account Key 不同),创建 CSR(Certificate Signing Request),发到 Order 的 finalize URL。

bash 复制代码
POST /acme/order/{id}/finalize
{
  "csr": "MIIBxTCCAWsCAQAwYjELMAkGA1UE..."  // Base64URL 编码的 CSR
}

CA 用自己的私钥签发证书,返回一个证书下载 URL。

第六步:下载证书

bash 复制代码
POST /acme/cert/{id}

返回 PEM 格式的证书链(你的证书 + 中间证书)。保存到文件,配到 Nginx 或其他 Web 服务器上就行了。

安全机制总结

ACME 协议在安全性上做了几个关键设计:

所有请求都用 JWS(JSON Web Signature)签名,CA 通过 Account Key 验证请求者身份。每个请求带 nonce 防重放。域名验证确保只有域名控制者才能申请证书。Account Key 和 Certificate Key 分离,降低单一密钥泄露的风险。

实际影响

理解 ACME 协议的意义不只是"知道原理":

当 certbot 报错时,你能根据错误发生在哪个阶段来定位问题。比如 DNS-01 验证失败,可能是 TXT 记录没生效(DNS 传播延迟);HTTP-01 失败,可能是服务器防火墙拦了 CA 的请求。

当你选择证书管理平台时,理解了 ACME 就知道平台实际上帮你做了什么------自动完成 DNS 验证(通过 DNS API 添加 TXT 记录)和证书签发,省掉了手动操作的环节。

延伸阅读

ACME 协议的完整规范在 RFC 8555,有兴趣可以读一下。Let's Encrypt 的文档里也有比较详细的流程说明。


这篇是纯协议解析,不涉及特定产品推荐。如果你对证书管理感兴趣,ssl.spug.cc 可以了解一下。

相关推荐
考虑考虑4 分钟前
kubectl命令
运维·后端·自动化运维
第五页的你20 分钟前
ElasticSearch结合本地消息表实现搜索功能
后端
谢亮_vipxieliang1 小时前
ValidX分组验证详解:不同场景使用不同验证规则
java·spring boot·后端·spring cloud·eclipse·hibernate
超兔一体云1 小时前
MySQL索引优化实战——从慢查询到索引调优
后端·mysql
. . . . .1 小时前
服务端监控
后端
凤山老林2 小时前
Spring Boot 集成 Spring Vault:集中式密钥管理与动态凭证轮换
spring boot·后端·spring·vault·集中式秘钥管理
雨夜之寂2 小时前
雨夜-现在有办法识别是不是ai文章么
后端·面试
2601_962071172 小时前
八. Spring Boot2 整合连接 Redis(超详细剖析)
spring boot·redis·后端
掘金者阿豪2 小时前
一次 413 Content Too Large 排查:真正的问题可能不在你的后端
后端
程序员贺加贝2 小时前
一次 SaaS ERP 主数据生命周期设计:Policy、PreCheck 与结构化阻断原因
java·后端·架构·saas