Skip to content

feat(wechatpay): 平台证书自动轮换(12h + 管理员可手动触发) - #7

Merged
worable233 merged 1 commit into
mainfrom
feat/wechatpay-cert-rotation
Oct 25, 2026
Merged

worable233 merged 1 commit into
mainfrom
feat/wechatpay-cert-rotation

Conversation

@worable233

Copy link
Copy Markdown
Owner

微信支付平台证书会轮换。之前「贴一张公钥/证书」的写法在生产上必然过期——到期那天所有回调突然 401,而错误信息只说「签名无效」。

做了什么

  • GET /v3/certificates 拉列表 → APIv3 密钥 AES-GCM 解密 → X509Certificate 解析出公钥与证书自身有效期(不是应答里的 expire_time 字段)
  • 先验签再采信:应答必须用现有平台公钥验过,否则等于让别人决定用什么公钥验证自己
  • PlatformKeyring 按 Wechatpay-Serial 选证书:轮换期间新旧并存,不能「用唯一一张」;未命中序列号时退回任一仍有效证书,没有则拒绝验签(不降级为放行)
  • 定时任务 platform-cert-refresh 每 12h,失败只 warn 不抛;后台另有「立即轮换」按钮
  • 过期证书不装:否则轮换失败时会拿废证书继续验签,症状同样是「回调全 401」

鸡生蛋(写清楚,免得以为配置项多余)

首次拉证书要验签,验签要公钥 —— 所以 platformPublicKey 仍是必填的 bootstrap,之后轮换才由任务接管。

验证

pnpm test 47 例(原 37 + 新增 10),关键几例:

  • 轮换前用新证书私钥签的回调被拒 401,轮换后同一报文通过并结算(bootstrap 与轮换证书用两把不同密钥,才证明密钥真换了)
  • 轮换应答签名无效 → 拒绝(用商户私钥签来冒充)
  • 过期证书被丢弃、列表为空明确报错、错误 APIv3 密钥解密失败
  • 激活时排期 platform-cert-refresh 每 12h 且有处理器

tsc / build-plugin 通过;前端加「证书张数 + 最早到期 + 立即轮换」,四语言目录更新,check-package-catalogs / i18n-hant --check 通过。

仍未验证

真实商户号下的轮换(需凭据),以及微信在轮换窗口内同时用新旧证书签名的真实时序。

微信支付平台证书会轮换,之前直接贴一张公钥/证书的写法在生产上必然过期 ——
到期那天所有回调突然 401,而错误信息只说「签名无效」。

## 做了什么

- `GET /v3/certificates` 拉取证书列表 → 用 APIv3 密钥 AES-GCM 解密 → `X509Certificate`
  解析出公钥与**证书自身**的有效期(不是应答里的 `expire_time` 字段)。
- **先验签再采信**:应答必须用现有平台公钥验过,否则等于让别人决定用什么公钥验证自己。
- `PlatformKeyring` 按 `Wechatpay-Serial` 选证书:轮换期间新旧并存,不能「用唯一一张」。
  未命中序列号时退回任一仍有效证书,没有则拒绝验签(不降级为放行)。
- 定时任务 `platform-cert-refresh` 每 12h 一次,失败只 warn 不抛(一次网关抖动不该
  让下一次轮换也停);后台另有「立即轮换」按钮。
- 过期证书**不装**:否则轮换失败时会拿废证书继续验签,症状同样是「回调全 401」。

## 鸡生蛋说明(写清楚,免得以为配置项是多余的)

首次拉证书要验签,验签要公钥 —— 所以 `platformPublicKey` 仍是必填的 bootstrap,
之后的轮换才由任务接管。

## 验证

`pnpm test` **47 例**(原 37 + 新增 10):
- 证书列表解密/序列号/真实有效期、「过期证书被丢弃」、「列表为空明确报错」、
  错误 APIv3 密钥解密失败;
- keyring 按序列号取值、未知序列号退回、无可用证书返回 undefined;
- 轮换端到端:**轮换前**用新证书私钥签的回调被拒 401、**轮换后**同一报文通过并结算
  (bootstrap 与轮换证书用两把不同密钥,才证明密钥真的换了);
- 轮换应答签名无效 → 拒绝(用商户私钥签来冒充);
- 激活时排期 `platform-cert-refresh` 每 12h 且有处理器。

`tsc` / `build-plugin` 通过;前端加「证书张数 + 最早到期 + 立即轮换」,四语言目录更新,
`check-package-catalogs` / `i18n-hant --check` 均通过。
@worable233
worable233 merged commit 6513453 into main Oct 25, 2026
1 check passed
@worable233
worable233 deleted the feat/wechatpay-cert-rotation branch October 25, 2026 07:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant