Skip to content

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_idtimestampnonce_strbody_digest 用换行符 \n 拼接:

签名串 = service_id + "\n" + timestamp + "\n" + nonce_str + "\n" + bodyDigest

示例:

SVC1234567890
1704067200
abc123def456
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

3. 生成签名

使用私钥对签名串进行 RSA-SHA256 签名,然后进行 Base64 编码:

javascript
sign = Base64(RSA-SHA256(签名串, privateKey))

4. 构建 Authorization Header

service_idtimestampnonce_strsign 组合成 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-----

密钥上传

  1. 登录米付科技商户平台
  2. 进入「密钥管理」页面
  3. 上传您的公钥文件
  4. 平台将返回平台公钥(用于验签)

注意事项

  1. 私钥保密: 商户私钥必须严格保密,不可泄露
  2. 公钥上传: 商户公钥需上传至平台,用于平台验证商户签名
  3. 平台公钥: 平台公钥用于商户验证平台返回数据的签名
  4. 定期更换: 建议定期更换密钥对,提高安全性
  5. 密钥长度: 必须使用 2048 位或以上密钥长度

验签流程

接收平台返回的响应时,需要验证平台签名:

  1. 提取响应数据中的 sign 字段
  2. 对响应体进行 SHA256 计算摘要
  3. 使用 service_idtimestampnonce_str、响应体摘要构造签名串
  4. 使用平台公钥验证签名
  5. 验证通过后才处理业务数据

签名参数说明

参数类型说明
service_idstring(32)服务标识,参与签名防止跨服务冒用
timestampstring(10)Unix 时间戳(秒),与服务器时间相差超过 5 分钟的请求将被拒绝
nonce_strstring(32)随机字符串,每次请求唯一,用于防止重放攻击
body_digeststring(64)请求体 SHA256 摘要,防止请求体被篡改

常见问题

Q: 签名验证失败怎么办?

  1. 检查请求体 JSON 序列化是否与签名时一致(注意空格、字段顺序)
  2. 确认 SHA256 摘要计算使用的是原始请求体字符串
  3. 检查签名串拼接格式是否正确(service_id\ntimestamp\nnonce_str\nbodyDigest
  4. 确认使用的私钥/公钥是否匹配
  5. 检查字符编码是否统一为 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位)

米付科技版权所有,保留所有权利