H5支付宝支付中的商户私钥和支付宝公钥如何配置?
明确结论
H5 支付是支付宝 alipay.trade.wap.pay 接口的一种使用场景,密钥配置规则与支付宝开放平台的其他接口一致:
- 商户私钥:由商户自行生成,用于请求签名,必须与上传到支付宝开放平台的”应用公钥”配对。
- 原始格式 RSA 私钥:通常是密钥工具生成的 PKCS#1 私钥。它能否直接填写到”商户私钥”配置项,取决于所用 SDK 或支付插件要求 PKCS#1 还是 PKCS#8 格式。
- 支付宝公钥:为应用配置”应用公钥”后,由支付宝开放平台提供,用于验证支付宝响应数据和异步通知的签名。它既不是本地生成的应用公钥,也不是商户私钥对应的公钥。
常见错误包括把”应用公钥”填入”支付宝公钥”字段,或者把带有头尾标记、换行和空格的私钥直接复制到只接受纯字符串的配置项中。
三种密钥分别是什么
密钥之间的关系可以简单理解为:
商户私钥 ──生成签名──> 支付宝验证商户请求
支付宝公钥 ──验证签名──> 商户验证支付宝通知和响应
商户在本地生成一对密钥:
商户私钥(也称应用私钥)
应用公钥
具体用法如下:
- 商户私钥只保存在商户服务器上,不能上传、公开或发送给他人。
- 应用公钥需要配置到支付宝开放平台。
- 应用公钥配置完成后,平台会显示对应的支付宝公钥。
- 商户需要把支付宝公钥复制到自己的系统中。
本地密钥工具生成的公钥通常是”应用公钥”,不能直接作为”支付宝公钥”使用。
正确配置步骤
1. 确认应用和签名模式
进入支付宝开放平台,找到实际用于 H5 支付的应用,确认以下信息:
app_id与商户系统中的配置一致;- 接口加签使用普通公钥模式还是证书模式;
- 签名算法通常为
RSA2,对应SHA256WithRSA。
密钥必须属于当前 app_id。测试应用、沙箱应用和正式应用的密钥不能混用。
2. 保存商户私钥
使用支付宝密钥工具生成密钥时,一般会得到应用私钥和应用公钥。应用私钥就是商户用于签名的私钥。
常见的私钥格式如下。
PKCS#1:
-----BEGIN RSA PRIVATE KEY-----
MIIE...
-----END RSA PRIVATE KEY-----
PKCS#8:
-----BEGIN PRIVATE KEY-----
MIIE...
-----END PRIVATE KEY-----
有些管理后台要求填写完整的 PEM 内容,包括头尾标记和换行;有些插件只接受中间的 Base64 字符串。具体格式应以当前 SDK 或插件的字段说明为准,不能只根据”商户私钥”这个字段名称判断。
如果配置项要求填写”纯私钥字符串”,需要删除:
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----
或者:
-----BEGIN PRIVATE KEY-----
-----END PRIVATE KEY-----
还要去掉换行、空格和不可见字符,只保留中间的 Base64 内容。
3. 上传应用公钥
把本地生成的”应用公钥”配置到支付宝开放平台对应应用的接口加签设置中。
公钥通常采用以下格式:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqh...
-----END PUBLIC KEY-----
如果平台要求粘贴纯字符串,也只需提交中间的 Base64 内容。不要把商户私钥上传到开放平台。
4. 获取支付宝公钥
应用公钥配置成功后,在该应用的接口加签配置页面查看并复制”支付宝公钥”。
需要注意:
应用公钥 ≠ 支付宝公钥
页面上的名称必须明确显示为”支付宝公钥”。不要从本地密钥工具中寻找支付宝公钥,也不要把本地生成的公钥再次填入商户系统的”支付宝公钥”字段。
5. 填入商户系统
使用普通公钥模式时,各配置项通常对应以下内容:
| 配置项 | 应填写内容 |
|---|---|
app_id | 支付宝开放平台中的应用 ID |
商户私钥、应用私钥或 merchant_private_key | 本地生成的私钥 |
支付宝公钥或 alipay_public_key | 开放平台显示的支付宝公钥 |
sign_type | 通常为 RSA2 |
charset | 通常为 UTF-8 |
notify_url | 可从公网访问的异步通知地址 |
配置示例
不同 SDK 对私钥格式的要求可能不同。下面是常见的”纯 Base64 字符串”配置方式:
$config = [
'app_id' => '2021000000000000',
'merchant_private_key' => 'MIIEvQIBADANBgkqhkiG9w0BAQEFAASC...',
'alipay_public_key' => 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...',
'sign_type' => 'RSA2',
'charset' => 'UTF-8',
];
如果 SDK 要求使用 PEM 格式,则需要保留头尾标记和换行:
$merchantPrivateKey = <<<'PEM'
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASC...
-----END PRIVATE KEY-----
PEM;
$alipayPublicKey = <<<'PEM'
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...
-----END PUBLIC KEY-----
PEM;
不要把真实密钥直接写入可公开访问的代码仓库。可以从环境变量或受权限保护的配置文件中读取:
$merchantPrivateKey = getenv('ALIPAY_MERCHANT_PRIVATE_KEY');
$alipayPublicKey = getenv('ALIPAY_PUBLIC_KEY');
如何检查私钥格式
可以使用 OpenSSL 判断私钥格式,并检查内容是否完整。
检查 PKCS#1 RSA 私钥:
openssl rsa -in merchant_private_key.pem -check -noout
检查 PKCS#8 私钥:
openssl pkey -in merchant_private_key.pem -check -noout
从私钥导出对应的公钥:
openssl pkey -in merchant_private_key.pem -pubout -out derived_public_key.pem
导出的公钥应与配置到支付宝开放平台的应用公钥一致。如果两者不匹配,说明商户私钥和应用公钥不属于同一密钥对,签名验证一定会失败。
把 PKCS#1 私钥转换为未加密的 PKCS#8 格式,可以使用:
openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem \
-outform PEM -nocrypt -out private_key_pkcs8.pem
转换不会改变密钥对本身。操作前应备份原文件,并严格限制私钥文件的访问权限。
复制后立即报错的常见原因
私钥格式不符合插件要求
例如,插件要求 PKCS#8,实际填写的私钥却以以下内容开头:
-----BEGIN RSA PRIVATE KEY-----
这种情况需要按照插件文档转换私钥格式,不能只删除头尾标记。
包含多余字符
从网页或编辑器复制密钥时,可能会带入以下内容:
- 空格或空行;
- 中文引号;
- 全角字符;
- HTML 标签;
- 不可见字符;
\n形式的字面字符串。
如果配置项要求纯字符串,内容中应只有 Base64 字符,通常包括字母、数字、+、/,末尾还可能有 =。
把应用公钥当成支付宝公钥
这种错误不一定会在保存配置时触发格式提示,但验证支付宝回调时通常会出现 sign check fail 或验签失败。
密钥与应用不对应
即使密钥格式正确,如果商户私钥对应的应用公钥没有配置到当前 app_id,调用接口时仍会提示签名错误。
RSA 与 RSA2 不一致
配置为 RSA2 时,签名和验签都应使用 SHA256WithRSA。不能一侧使用 RSA,另一侧使用 RSA2。
普通公钥模式和证书模式混用
如果开放平台使用证书模式,系统通常需要配置:
- 应用公钥证书;
- 支付宝公钥证书;
- 支付宝根证书。
这种情况下,不能只填写一个”支付宝公钥”字符串。反过来,普通公钥模式也不应填写证书序列号或证书文件内容。
排查建议
可以先根据报错出现的阶段缩小范围:
- 保存配置时立即报错:先检查字段格式、PKCS#1 或 PKCS#8 格式、头尾标记和换行。
- 调用支付接口时提示签名错误:检查商户私钥、应用公钥、
app_id和sign_type是否对应。 - 支付成功,但异步通知验签失败:检查是否误用了应用公钥,以及验签时使用的是否为支付宝公钥。
- 只有正式环境或沙箱环境失败:检查是否混用了两个环境的应用 ID 和密钥。
不要在日志、截图或排错信息中展示完整的商户私钥。如果私钥已经泄露,应重新生成密钥对,并在支付宝开放平台更新应用公钥。
备注:内容仅供参考。
