Skip to content

签名与安全

所有服务端接口均需 HMAC 签名。secret 只存在你的服务器,不允许出现在浏览器或客户端。

请求头

说明
X-App-Id应用编号
X-TimestampUnix 秒级时间戳;与服务端偏差 ≤ ±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"

回调通知也用同一套签名,验签方式见回调通知