主题
签名与安全
所有服务端接口均需 HMAC 签名。secret 只存在你的服务器,不允许出现在浏览器或客户端。
请求头
| 头 | 说明 |
|---|---|
X-App-Id | 应用编号 |
X-Timestamp | Unix 秒级时间戳;与服务端偏差 ≤ ±5 分钟 |
X-Nonce | 随机串(建议 32 位);8 小时内不得重复,否则 401 REPLAY_NONCE |
X-Signature | 签名 = hex(HMAC-SHA256(app_secret, 签名串)) |
签名串
签名串 = METHOD \n PATH \n QUERY \n X-Timestamp \n X-Nonce \n body(原始字节)METHOD大写(POST/GET);PATH如/v1/open/payments;QUERY为原始 query string(不重排、不解码),无则空串;body为原始请求字节(不是重新序列化后的 JSON)——请先序列化一次,签名与发送用同一份字节。
示例代码
Go
go
func sign(secret, method, path, query, ts, nonce string, body []byte) string {
raw := method + "\n" + path + "\n" + query + "\n" + ts + "\n" + nonce + "\n"
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(raw))
mac.Write(body)
return hex.EncodeToString(mac.Sum(nil))
}PHP
php
function sign(string $secret, string $method, string $path, string $query,
string $ts, string $nonce, string $body): string {
$raw = implode("\n", [$method, $path, $query, $ts, $nonce]) . "\n" . $body;
return hash_hmac('sha256', $raw, $secret);
}curl 快速验证
bash
TS=$(date +%s); NONCE=$(head -c16 /dev/urandom | xxd -p)
BODY='{"out_trade_no":"SHOP-A-20260901-0001","amount":1000,"subject":"测试订单"}'
SIG=$(printf 'POST\n/v1/open/payments\n\n%s\n%s\n%s' "$TS" "$NONCE" "$BODY" \
| openssl dgst -sha256 -hmac "$APP_SECRET" | awk '{print $2}')
curl -X POST "https://<host>/v1/open/payments" \
-H "X-App-Id: $APP_ID" -H "X-Timestamp: $TS" -H "X-Nonce: $NONCE" \
-H "X-Signature: $SIG" -H "Content-Type: application/json" -d "$BODY"回调通知也用同一套签名,验签方式见回调通知。