Skip to content

v2 协议规范

本页是商户 API v2 的协议规范:加密、签名、防重放与请求/响应格式。对接前请先在 凭据与密钥 页确认已拿到 4 项凭据;写完代码后务必用 上线自检 selfcheck 跑通整条链路。

1. 协议概览

商户与平台的所有业务请求/响应/回调均经过:

  • 加密:RSA-OAEP(MGF1 = SHA-1),保护请求/响应内容。
  • 签名:SHA256withRSA,保证完整性与来源可信。
  • 防重放:时间戳 + nonce,请求与回调双向校验。

业务参数以 JSON 表示,加密为密文后作为 HTTP body 传输。

2. 核心规范(务必逐字节对齐)

2.1 加密:RSA-OAEP,MGF1 = SHA-1

  • 明文按 214 字节分段,逐段 RSA-OAEP 加密,密文拼接后整体 Base64。
  • 解密:Base64 解码后按 256 字节分段,逐段解密后拼接。
  • ⚠️ 头号互通坑:OAEP 的哈希必须是 SHA-1。很多语言默认 OAEP-SHA256,两边不一致会解不开。各语言显式写法:
php
// 默认即 SHA-1
openssl_public_encrypt($d, $o, $k, OPENSSL_PKCS1_OAEP_PADDING)
python
padding.OAEP(mgf=MGF1(SHA1()), algorithm=SHA1(), label=None)
js
{ padding: RSA_PKCS1_OAEP_PADDING, oaepHash: 'sha1' }
go
rsa.EncryptOAEP(sha1.New(), rand.Reader, pub, msg, nil)
java
Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding")

2.2 签名:SHA256withRSA(PKCS#1 v1.5 签名填充)

2.3 canonical 签名串(规范,不是示例)

签名 / 验签的输入必须是下面这串,三段以**换行符 \n(LF,0x0A)**连接,逐字节一致,否则 100% 验签失败:

ANONY-TIMESTAMP + "\n" + ANONY-NONCE + "\n" + <body>
  • 上行请求<body> = 加密后的请求体(即 HTTP body,Base64 密文)。
  • 下行响应 / 回调<body> = 响应体(Base64 密文)。

2.4 防重放

  • ANONY-TIMESTAMP:秒级 Unix 时间戳。服务端时间窗 ±5 分钟(即 ±300 秒),超出拒绝。
  • ANONY-NONCE≥16 字节 CSPRNG 随机串(hex / base64 均可,建议定长 hex)。服务端对 (商户号, nonce) 去重,重复即拒绝
  • 回调方向同样如此:平台回调你时也会带 ANONY-TIMESTAMP / ANONY-NONCE你必须自行校验时间窗并对 nonce 去重,以拒绝被重放的回调(建议用 Redis SET key 1 NX EX 900 之类的原子去重,过期 ≥ 15 分钟)。回调侧的完整处理步骤见 回调机制

3. 请求与响应格式

3.1 上行请求头

ANONY-APP-ID:    <商户号>
ANONY-TOKEN:     <token>
ANONY-TIMESTAMP: <秒级时间戳>
ANONY-NONCE:     <≥16字节随机串>
ANONY-SIGN:      <canonical 串的 SHA256withRSA 签名, base64>
请求体(body):     <业务 JSON 经 OAEP 加密后的 base64 密文>

其中 ANONY-TOKEN 通过 getToken 获取。

3.2 下行响应体

json
{ "code": 10000, "data": "<base64 密文>", "message": "success" }
  • code == 10000 表示成功;dataOAEP 加密的 base64 密文,需验签后解密。
  • 响应头带 ANONY-TIMESTAMP / ANONY-NONCE / ANONY-SIGN
  • ⚠️ 解析外层 JSON 请使用标准 JSON 库(响应体里 / 可能被转义为 \/,标准库会自动还原;不要手写字符串切割)。

3.3 处理下行的步骤

  1. 用标准 JSON 库解析外层 {code,data,message}
  2. 校验 ANONY-TIMESTAMP 在 ±5 分钟内,且 ANONY-NONCE 未见过(去重)。
  3. canonical(ts, nonce, data) + 平台公钥 验签。
  4. 商户私钥 OAEP 解密 data,得到业务 JSON。

code != 10000 时的错误码含义见 错误码;验签/解密失败的排查见 排障指南

4. 实现细节补充

token 生命周期(实现细节补充)

ANONY-TOKEN 采用滑动过期 8 小时 + 绝对上限 24 小时:每次成功调用会刷新 8 小时有效期,但自签发起最长存活 24 小时。收到 tokenExpired 时重新调用 getToken 即可,无需在本地精确计时。

请求体大小上限(实现细节补充)

请求体(加密后的 Base64 密文)上限为 128KB,超限会在协议校验之前被直接拒绝(报 paramError)。正常业务请求远小于该上限;若触发,请检查是否误将大对象塞进了业务 JSON。

v1 协议简述(实现细节补充,新商户请忽略)

存量老商户使用 v1 协议:MD5withRSA 验签(对密文 body)+ PKCS#1 v1.5 分段加解密,无时间戳/nonce 防重放头。v1 仅面向存量商户,新接入一律 v2。协议版本由平台侧数据库按商户号决定,请求侧无法通过任何头或参数切换/降级(防降级攻击);从 v1 升级 v2 需先通过 selfcheck 自检,再由平台完成切换。

5. 安全须知

  • 私钥仅存于你的服务端,切勿写入前端、日志或第三方。
  • 始终校验下行签名后再使用数据;始终对回调做时间窗 + nonce 去重。
  • 时间戳依赖系统时钟,请确保服务器 NTP 同步(否则易触发 ±5 分钟超窗)。
  • 算法分支由平台按商户号决定,请求侧无法更改(防降级)。

下一步:按 API 参考 逐个接口对接,或直接使用 官方 SDK(PHP / Python / Node / Go / Java)跳过手写协议细节。