Appearance
RSA 签名机制
概述
米付科技聚合支付平台采用 RSA 非对称加密 签名机制,确保接口请求的安全性和完整性。所有接口请求都需要进行签名验证。
签名算法
- 签名算法: RSA-SHA256
- 编码方式: Base64
- 密钥长度: 2048 位
签名流程
1. 计算请求体摘要
对请求体(JSON 字符串)进行 SHA256 计算,得到固定长度的摘要值:
javascript
const body = JSON.stringify({
merchant_no: "1234567890",
out_trade_no: "20240101120000",
total_amount: 100
});
const bodyDigest = SHA256(body);
// 例如: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"2. 构造签名串
将 service_id、timestamp、nonce_str、body_digest 用换行符 \n 拼接:
签名串 = service_id + "\n" + timestamp + "\n" + nonce_str + "\n" + bodyDigest示例:
SVC1234567890
1704067200
abc123def456
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8553. 生成签名
使用私钥对签名串进行 RSA-SHA256 签名,然后进行 Base64 编码:
javascript
sign = Base64(RSA-SHA256(签名串, privateKey))4. 构建 Authorization Header
将 service_id、timestamp、nonce_str、sign 组合成 Authorization Header:
Authorization: RSA service_id=SVC1234567890,timestamp=1704067200,nonce_str=abc123def456,sign=签名值签名流程示意
请求体(JSON) ──SHA256──→ body_digest ──┐
├─ 拼接签名串 ──RSA-SHA256──→ 签名值
service_id ───────────────────────────┘
timestamp ─────────────────────────────┘
nonce_str ─────────────────────────────┘密钥管理
生成密钥对
使用 OpenSSL 生成
bash
# 生成私钥(2048位)
openssl genrsa -out private_key.pem 2048
# 生成公钥
openssl rsa -in private_key.pem -pubout -out public_key.pem密钥格式
私钥格式(PKCS#8):
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...
...
-----END PRIVATE KEY-----公钥格式:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
...
-----END PUBLIC KEY-----密钥上传
- 登录米付科技商户平台
- 进入「密钥管理」页面
- 上传您的公钥文件
- 平台将返回平台公钥(用于验签)
注意事项
- 私钥保密: 商户私钥必须严格保密,不可泄露
- 公钥上传: 商户公钥需上传至平台,用于平台验证商户签名
- 平台公钥: 平台公钥用于商户验证平台返回数据的签名
- 定期更换: 建议定期更换密钥对,提高安全性
- 密钥长度: 必须使用 2048 位或以上密钥长度
验签流程
接收平台返回的响应时,需要验证平台签名:
- 提取响应数据中的
sign字段 - 对响应体进行 SHA256 计算摘要
- 使用
service_id、timestamp、nonce_str、响应体摘要构造签名串 - 使用平台公钥验证签名
- 验证通过后才处理业务数据
签名参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
| service_id | string(32) | 服务标识,参与签名防止跨服务冒用 |
| timestamp | string(10) | Unix 时间戳(秒),与服务器时间相差超过 5 分钟的请求将被拒绝 |
| nonce_str | string(32) | 随机字符串,每次请求唯一,用于防止重放攻击 |
| body_digest | string(64) | 请求体 SHA256 摘要,防止请求体被篡改 |
常见问题
Q: 签名验证失败怎么办?
- 检查请求体 JSON 序列化是否与签名时一致(注意空格、字段顺序)
- 确认 SHA256 摘要计算使用的是原始请求体字符串
- 检查签名串拼接格式是否正确(
service_id\ntimestamp\nnonce_str\nbodyDigest) - 确认使用的私钥/公钥是否匹配
- 检查字符编码是否统一为 UTF-8
Q: 是否支持其他签名算法?
当前仅支持 RSA-SHA256 签名算法,暂不支持 MD5、HMAC 等其他算法。
Q: 时间戳精度和有效期?
- 精度: Unix 时间戳,秒级(10 位数字)
- 有效期: 与服务器时间相差超过 5 分钟 的请求将被拒绝
- 示例:
1704067200(2024-01-01 00:00:00 UTC)
javascript
// 获取秒级时间戳
const timestamp = Math.floor(Date.now() / 1000).toString();Q: nonce_str 有什么要求?
- 长度: 必须为 32 个字符
- 字符: 仅允许字母和数字(a-z、A-Z、0-9)
- 唯一性: 同一
service_id下每次请求必须不同 - 推荐生成方式: UUID v4 去掉横线,或 32 位随机十六进制字符串
javascript
// Node.js 示例
const crypto = require('crypto');
const nonce_str = crypto.randomBytes(16).toString('hex');
// 输出: "a1b2c3d4e5f67890a1b2c3d4e5f67890" (32位)