PAYATHON 2026

支付宝支付与转账加签方式冲突及签名错误如何解决

支付阿杰

结论

同一个支付宝应用只能选择一种接口加签方式,不能同时使用“公钥模式”和“证书模式”。

如果转账接口要求使用证书模式,就需要将整个应用切换为证书模式。支付接口仍使用应用私钥生成 RSA2 签名,同时还需要配置:

  • 应用私钥
  • 应用公钥证书
  • 支付宝公钥证书
  • 支付宝根证书

使用证书模式并不等于不再使用私钥。无论采用公钥模式还是证书模式,请求都由应用私钥签名。区别主要在于支付宝如何识别应用公钥,以及 SDK 如何获取并验证支付宝公钥。

如果某个支付产品或旧版接口明确不支持证书模式,需要先确认该接口当前的接入规则。若确实无法统一,可以考虑用两个不同的支付宝应用分别接入。不过,应用与商户、产品权限、资金账户之间能否这样拆分,要以支付宝开放平台的实际配置为准。

推荐配置方式

在支付宝开放平台中,将应用的“接口加签方式”设置为证书模式,然后重新下载当前应用对应的三份证书:

appCertPublicKey_应用APPID.crt
alipayCertPublicKey_RSA2.crt
alipayRootCert.crt

程序还要使用生成应用公钥证书时对应的应用私钥。这四项配置不能来自不同应用、不同环境或不同换证批次。

以 Java SDK 为例:

AlipayConfig config = new AlipayConfig();
config.setServerUrl("https://openapi.alipay.com/gateway.do");
config.setAppId("你的APPID");
config.setPrivateKey("应用私钥");
config.setFormat("json");
config.setCharset("UTF-8");
config.setSignType("RSA2");

config.setAppCertPath("/path/to/appCertPublicKey_APPID.crt");
config.setAlipayPublicCertPath("/path/to/alipayCertPublicKey_RSA2.crt");
config.setRootCertPath("/path/to/alipayRootCert.crt");

AlipayClient alipayClient = new DefaultAlipayClient(config);

支付和转账应共用这套客户端配置,不要在调用支付接口时切回普通公钥模式。

不同版本的支付宝 SDK 可能使用不同的构造方法和证书配置方式。有些版本支持直接传入证书内容,有些版本要求提供证书文件路径。具体应以当前 SDK 提供的 AlipayConfig 或证书模式构造方法为准。

公钥模式与证书模式不要混用

普通公钥模式通常使用类似下面的配置:

AlipayClient alipayClient = new DefaultAlipayClient(
    "https://openapi.alipay.com/gateway.do",
    appId,
    appPrivateKey,
    "json",
    "UTF-8",
    alipayPublicKey,
    "RSA2"
);

最后一个公钥参数必须填写“支付宝公钥”,不能填写应用公钥。

切换到证书模式后,不应继续使用普通公钥模式的构造方式,也不能只增加一个应用证书文件。证书模式需要完整配置三份证书,SDK 还会根据证书生成并提交 app_cert_sn、alipay_root_cert_sn 等参数。

如何验证应用私钥是否匹配

请求由应用私钥签名,支付宝使用平台中登记的应用公钥或应用公钥证书验签。因此,遇到 isv.invalid-signature 等签名错误时,应先检查应用私钥是否与平台登记的信息匹配。

验证普通公钥模式

从应用私钥重新导出公钥:

openssl pkey \
  -in app_private_key.pem \
  -pubout \
  -out derived_public_key.pem

分别计算导出公钥和原应用公钥的 DER 指纹:

openssl pkey \
  -pubin \
  -in derived_public_key.pem \
  -outform DER |
openssl dgst -sha256
openssl pkey \
  -pubin \
  -in app_public_key.pem \
  -outform DER |
openssl dgst -sha256

如果两个 SHA-256 结果相同,说明私钥与应用公钥匹配。

不要直接比较 PEM 文件的文本。换行、头尾标记或字符编码不同,都可能造成文本不一致,但实际公钥仍然完全相同。

验证证书模式

先从应用公钥证书中提取公钥:

openssl x509 \
  -in appCertPublicKey_APPID.crt \
  -pubkey \
  -noout \
  > cert_public_key.pem

再分别计算证书公钥和私钥导出公钥的指纹:

openssl pkey \
  -pubin \
  -in cert_public_key.pem \
  -outform DER |
openssl dgst -sha256
openssl pkey \
  -in app_private_key.pem \
  -pubout \
  -outform DER |
openssl dgst -sha256

如果两个结果相同,说明应用私钥与应用公钥证书匹配。

还可以检查证书中的应用信息和有效期:

openssl x509 \
  -in appCertPublicKey_APPID.crt \
  -noout \
  -subject \
  -issuer \
  -serial \
  -dates

检查时重点确认:

  • 证书对应的 APPID 是否与当前请求使用的应用一致。
  • 证书是否已经过期。
  • 证书是否属于正式环境,而非沙箱环境。
  • 换证后,程序是否仍在加载旧证书或旧私钥。

如何做最小化签名验证

可以用一段固定内容,检查私钥签名和证书公钥验签能否形成闭环:

printf '%s' 'alipay-sign-test' > content.txt

openssl dgst \
  -sha256 \
  -sign app_private_key.pem \
  -out signature.bin \
  content.txt

openssl dgst \
  -sha256 \
  -verify cert_public_key.pem \
  -signature signature.bin \
  content.txt

如果输出:

Verified OK

说明这组私钥和公钥可以完成 SHA256withRSA 签名验证。

这项测试只能证明密钥匹配,不能证明支付宝请求参数的待签名字符串、字符集和证书序列号一定正确。

支付宝公钥和支付宝公钥证书的作用

这里需要分清三项配置:

  • 应用私钥:由商户保存,用于签署请求。
  • 应用公钥或应用公钥证书:登记在支付宝平台,供支付宝验证请求。
  • 支付宝公钥或支付宝公钥证书:由支付宝提供,供应用验证支付宝返回结果和异步通知。

因此:

  • 支付宝返回“请求签名错误”时,通常先检查应用私钥、应用公钥证书、APPID 和签名参数。
  • 本地提示“支付宝响应验签失败”时,通常先检查支付宝公钥或支付宝公钥证书,以及验签时使用的原始响应内容。

不能用应用公钥验证支付宝响应,也不能把支付宝公钥填到应用公钥的位置。

签名错误排查顺序

1. 检查环境和 APPID

确认以下内容属于同一环境和同一应用:

网关地址
APPID
应用私钥
应用公钥证书
支付宝公钥证书
支付宝根证书

正式环境通常使用:

https://openapi.alipay.com/gateway.do

沙箱应用、沙箱密钥或沙箱证书不能直接用于正式环境。

2. 检查平台加签模式

如果开放平台选择了证书模式,代码也必须按证书模式初始化 SDK。平台使用证书模式,代码却按普通公钥模式调用,是常见的失败原因。

切换加签方式或重新生成证书后,还要确认新配置已经生效,并重启仍在使用旧配置的应用实例。

3. 检查 sign_type

建议统一使用:

RSA2

RSA2 对应 SHA256withRSA。平台、SDK 配置和手工签名代码不能混用 RSA 与 RSA2。

4. 检查私钥格式

Java SDK 一般需要 PKCS#8 格式的 RSA 私钥。如果当前私钥是 PKCS#1 格式,可以进行转换:

openssl pkcs8 \
  -topk8 \
  -inform PEM \
  -in rsa_private_key.pem \
  -outform PEM \
  -nocrypt \
  -out app_private_key_pkcs8.pem

如果将 PEM 内容放入配置中心或环境变量,需要检查:

  • \n 是否被保存成两个普通字符。
  • Base64 内容是否被误删。
  • 内容中是否有多余的空格或引号。
  • 配置中心是否仍保存着旧私钥。
  • 私钥是否被截断。

5. 不要手工修改 SDK 生成的公共参数

使用支付宝 SDK 时,应尽量由 SDK 生成:

sign
timestamp
app_cert_sn
alipay_root_cert_sn

不要对 SDK 已经签名的参数再次进行 URL 编码、重新排序或修改。签名完成后,任何字段发生变化都可能导致验签失败。

业务参数中的 JSON 也应交给 SDK 序列化,或确保原始内容保持一致。例如,签名后改变空格、转义字符、字段值或字符编码,都会改变待签名内容。

6. 检查证书加载路径

相同代码在其他客户处运行正常,只能说明调用流程大体没有问题,不能证明当前客户的配置正确。需要重点检查:

  • 相对路径是否指向了错误的文件。
  • 容器或服务器挂载的是否仍是旧证书。
  • 文件名虽然正确,文件内容是否来自另一个应用。
  • 多租户缓存是否按 APPID 隔离。
  • 创建 AlipayClient 时是否复用了其他客户的实例。
  • 配置更新后是否重新初始化了客户端对象。

多商户系统应按 APPID 保存完整且相互独立的配置。不能只切换私钥,却继续使用另一应用的证书或支付宝公钥。

最终建议

建议按以下方式处理:

  1. 将需要支付和转账的应用统一设置为证书模式。
  2. 使用同一个应用私钥调用两个接口。
  3. 重新下载该应用的三份证书,不要复用历史文件。
  4. 使用 OpenSSL 验证应用私钥是否与应用公钥证书中的公钥匹配。
  5. 确认 APPID、网关、证书、私钥和 RSA2 属于同一应用及同一环境。
  6. 为每个客户分别创建并缓存 AlipayClient,不要跨客户复用密钥和证书配置。
  7. 如果密钥匹配后仍然报错,记录支付宝返回的 code、sub_code、sub_msg 和请求时间,再结合脱敏后的公共参数排查。不要在日志或工单中输出完整的应用私钥。

备注:内容仅供参考。