跳到主要内容

签名方法

为了防止 API 调用过程中被恶意篡改,调用任何一个 API 都需要携带签名,服务端也会对响应进行签名。本文将使用一组测试密钥,以调用扫码收款接口为例,一步一步介绍如何计算签名。

提示

本文中的签名值仅作文档参考,请以实际计算结果为准。

签名算法

使用 HMAC-SHA256 算法,以终端密钥(Secret)对签名串进行 HMAC-SHA256 运算,结果进行 Base64 编码。

获取密钥

终端签名密钥在设备激活时由平台分配,通过激活设备接口响应中的 sign_secret 字段返回。激活流程详见设备接入

假设你的测试参数如下:

参数
商户号100001
密钥序列号KEY001
终端密钥(Secret)test_secret_key_1234567890abcdefghijklmnop

如何构造请求签名

第一步:构造签名串

签名串一共有 5 个部分,每一行为一个参数,结尾以 \n(换行符,ASCII 编码值为 0x0A)结束,包括最后一行。如果参数本身以 \n 结束,也需要附加一个 \n

HTTP请求方法\n
URL\n
请求时间戳\n
请求随机串\n
请求报文主体\n

扫码收款接口为例,逐行说明:

1. 获取 HTTP 请求方法

POST

2. 获取请求的 URL,去除域名部分

/open/cashier/trans/micropay
信息
  • 请求 URL 不包含域名和 Query String
  • 若存在 Query String,则拼接为 URL?QueryString

3. 获取发起请求时的系统当前时间戳,即格林威治时间 1970 年 01 月 01 日 00 时 00 分 00 秒起至现在的总秒数。服务端会拒绝处理很久之前发起的请求,请保持自身系统的时间准确。

1715049600

4. 生成一个请求随机串,推荐调用随机数函数生成,将得到的值转换为字符串。

a1b2c3d4e5f67890

5. 获取请求中的请求报文主体(request body),即原始 JSON 字符串。

{"amount":100,"out_trade_no":"TS20260507000001","auth_code":"134567890123456789"}
信息
  • 请求体为原始 JSON 字符串,GET 请求时请求体为空字符串
  • 计算签名时 body 是怎样的,发起请求时 body 就应该是怎样的

6. 按照上述规则,构造的请求签名串如下:

POST\n
/open/cashier/trans/micropay\n
1715049600\n
a1b2c3d4e5f67890\n
{"amount":100,"out_trade_no":"TS20260507000001","auth_code":"134567890123456789"}\n
注意

当请求报文主体为空串时,只需附加一个 \n,例如:

GET\n
/open/cashier/terminal/info\n
1715049600\n
a1b2c3d4e5f67890\n
\n

第二步:计算签名值

使用终端密钥(Secret)对签名串进行 HMAC-SHA256 运算,结果进行 Base64 编码得到签名值。

使用命令行演示(将签名串保存为 sign_string.txt):

echo -n -e 'POST\n/open/cashier/trans/micropay\n1715049600\na1b2c3d4e5f67890\n{"amount":100,"out_trade_no":"TS20260507000001","auth_code":"134567890123456789"}\n' \
| openssl dgst -sha256 -hmac "test_secret_key_1234567890abcdefghijklmnop" -binary \
| openssl base64 -A

得出的签名值如下:

qwT9ImMZdg67+59lmbPkdMX2Jj70og6hNdIha/yQQDs=

第三步:设置 Authorization Header

将签名信息放入 HTTP 请求头 Authorization 中,格式如下:

Authorization: KP-CASHIER-HMAC-SHA256 mchid="{商户号}", serial="{密钥序列号}", nonce="{随机串}", timestamp="{时间戳}", signature="{签名值}"

各字段说明:

字段说明
mchid发起请求的商户号
serial密钥序列号,用于声明所使用的密钥
nonce请求随机串,需与构造签名串时的随机串保持一致
timestamp请求时间戳,需与构造签名串时的时间戳保持一致
signature签名值,第二步计算得出的结果
信息

以上五项签名信息,无顺序要求。

示例:

Authorization: KP-CASHIER-HMAC-SHA256 mchid="100001", serial="KEY001", nonce="a1b2c3d4e5f67890", timestamp="1715049600", signature="qwT9ImMZdg67+59lmbPkdMX2Jj70og6hNdIha/yQQDs="

第四步:设置客户端信息 Header

每个请求需在 Ikudot-Cashier-Client Header 中携带客户端信息,详见客户端信息

完整请求示例

组合以上步骤,一个包含了签名的完整 HTTP 请求如下:

curl -X POST \
https://xxxx/open/cashier/trans/micropay \
-H 'Authorization: KP-CASHIER-HMAC-SHA256 mchid="100001", serial="KEY001", nonce="a1b2c3d4e5f67890", timestamp="1715049600", signature="qwT9ImMZdg67+59lmbPkdMX2Jj70og6hNdIha/yQQDs="' \
-H 'Ikudot-Cashier-Client: sn="SN-DEVICE-001", name="收银台A01", ip="192.168.1.100", app="cashier-pos", version="2.0.0", session="abc123def456"' \
-H 'Content-Type: application/json' \
-d '{"amount":100,"out_trade_no":"TS20260507000001","auth_code":"134567890123456789"}'

响应验签

服务端对成功响应(HTTP 2xx)会进行签名,签名信息通过以下响应头返回:

响应头说明
Ikudot-Cashier-Nonce响应随机串
Ikudot-Cashier-Signature响应签名值
Ikudot-Cashier-Timestamp响应时间戳
Ikudot-Cashier-Serial签名密钥序列号
Ikudot-Cashier-Signature-Type签名算法类型

响应签名串构造

时间戳\n
随机串\n
响应体\n

验签步骤

  1. 读取响应头中的时间戳、随机串和签名值
  2. 拼接响应签名串:时间戳\n随机串\n响应体\n
  3. 使用终端密钥(Secret)验证签名

安全要求

  • 时间戳与服务器时间偏差不得超过 30 分钟,否则请求将被拒绝
  • 同一随机串(nonce)在时间窗口内不可重复使用,防止重放攻击
  • 请求体大小不得超过 1MB

签名示例