1. 开发指南
GlobalPay
  • 开发指南
    • 开发前必读
    • 申请API Key 与 API Secret
    • 签名认证
    • 错误码参考
    • 订单状态
    • 常见问题
    • 支付回调通知
  • Api使用指南
    • 查询⽀持的资产
      GET
    • 创建订单
      POST
    • 查询订单
      GET
    • 取消订单
      POST
  1. 开发指南

签名认证

API 请求签名认证说明#

本文档说明 API 请求的签名认证机制。每个渠道商将分配一个唯一的密钥对: api_key, api_secret。其中 api_secret 用于对请求进行签名以供 BKJ 验证请求的合法性。

概述#

所有需要认证的请求均需进行签名认证,以保证请求的完整性、身份认证并防止重放攻击。签名使用 HMAC-SHA256 算法生成。

必需请求头#

所有需签名的请求必须包含以下头部:
Header是否必需说明示例
X-Api-Key是API KeyFCWbmJJi5ixxxxx_knMIZ36kL5ZPtBvxxxxxxxxxxxx
X-Signature是请求签名(HMAC-SHA256 的64位十六进制字符串)a1b2c3d4e5f6789...
X-Timestamp是请求时间戳(Unix秒级时间戳)1704067200
X-Nonce是请求唯一标识,用于防重放550e8400e29b41d4a716446655440000

签名生成流程#

第 1 步:准备签名数据#

需要准备以下元素:
1.
HTTP 方法(Method):例如 GET、POST、PUT、PATCH、DELETE(大写)
2.
请求路径(Path):URL 的 path 部分,不包含域名与 query 参数
示例:/openapi/v1/users
3.
Query 参数(Query):URL 中的查询参数,需要按 key 排序
示例:param1=value1&param2=value2
4.
请求时间戳(Timestamp):Unix 秒级时间戳
示例:1704067200
5.
请求体哈希(Body Hash):请求体的 SHA256 哈希值(十六进制)
如果是 JSON,先规范化后再计算哈希
如果无请求体,使用空字符串
6.
随机数(Nonce): 32 位 uuid,用于防重放攻击
注意 uuid 中不需要添加 -

第 2 步:Query 参数排序#

Query 参数需要按 key 的字母顺序(ASCII)排序:
示例:
原始 query:c=3&a=1&b=2
排序后:a=1&b=2&c=3

第 3 步:请求体处理#

3.1 JSON 请求体规范化#

如果请求体是 JSON 格式,需要先进行规范化:
规范化规则:
1.
递归对所有对象的键按字母序(ASCII)排序
2.
保留数组顺序不变
3.
数字保持原样(不转换为字符串)
4.
保留 null 值
5.
不添加额外空格
示例:
原始 JSON:
{
  "name": "John",
  "age": 25,
  "email": null,
  "hobbies": ["reading", "gaming"],
  "address": {
    "zip": 10001,
    "city": "New York"
  }
}
规范化后:
{"address":{"city":"New York","zip":10001},"age":25,"email":null,"hobbies":["reading","gaming"],"name":"John"}

3.2 计算 Body Hash#

对规范化后的 JSON 字符串(或原始请求体)计算 SHA256 哈希:
bodyHash = SHA256(normalizedBody)
结果为十六进制字符串,例如:a3b2c1d4e5f6...
注意:
如果请求体为空,bodyHash 为空字符串 ""
非 JSON 请求体直接计算 SHA256

第 4 步:拼接签名字符串#

按顺序拼接如下字符串(使用换行符 \n 分隔):
signString = method + '\n' + path + '\n' + sortedQuery + '\n' + timestamp + '\n' + bodyHash + '\n' + nonce
示例 1(带 Query 参数和 Body):
POST
/openapi/v1/users
a=1&b=2
1704067200
a3b2c1d4e5f6789...
bbcb94189ec932ac4d644da59045eb3c
示例 2(无 Query 参数和 Body):(6个部分,第2行path前、第5行body hash为空字符串)
GET

/openapi/v1/users

1704067200

bbcb94189ec932ac4d644da59045eb3c

第 5 步:生成 HMAC-SHA256 签名#

使用 API Secret 对签名字符串做 HMAC-SHA256,然后将结果用十六进制编码表示:
signature = HMAC-SHA256(signString, apiSecret)
将得到的十六进制字符串作为 X-Signature 头的值。

完整示例#

示例 1:POST 请求(带 JSON Body)#

请求信息:
方法:POST
路径:/openapi/v1/users
Query:无
Body:
{
  "name": "John Doe",
  "age": 30,
  "email": "john@example.com"
}
Timestamp:1704067200
Nonce: bbcb94189ec932ac4d644da59045eb3c
API Secret:SbBinP246GGC2Bs2UbH11QN40_****_0L5VkrEwc3uFxt0zhVU9KZoHwVxDMA-****h6J2lyQcK6A
步骤:
1.
规范化 Body:
{"age":30,"email":"john@example.com","name":"John Doe"}
2.
计算 Body Hash(SHA256):
3.
拼接签名字符串:
POST
/openapi/v1/users

1704067200
5d7e8f9a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e
bbcb94189ec932ac4d644da59045eb3c
4.
生成签名(HMAC-SHA256):
5.
最终请求头:
X-Api-Key: ak_your_api_key_here
X-Signature: <计算出的签名>
X-Timestamp: 1704067200
X-Nonce: bbcb94189ec932ac4d644da59045eb3c
Content-Type: application/json

示例 2:GET 请求(带 Query 参数)#

请求信息:
方法:GET
路径:/openapi/v1/users
Query:page=1&page_size=10&sort=name
Body:无
Timestamp:1704067200
Nonce:bbcb94189ec932ac4d644da59045eb3c
API Secret:SbBinP246GGC2Bs2UbH11QN40_****_0L5VkrEwc3uFxt0zhVU9KZoHwVxDMA-****h6J2lyQcK6A
步骤:
1.
排序 Query 参数:
page=1&page_size=10&sort=name
2.
Body Hash:空字符串(无 Body)
3.
拼接签名字符串:
GET
/openapi/v1/users
page=1&page_size=10&sort=name
1704067200

bbcb94189ec932ac4d644da59045eb3c
4.
生成签名:
5.
最终请求:
GET /openapi/v1/users?page=1&page_size=10&sort=name HTTP/1.1
X-Api-Key: ak_your_api_key_here
X-Signature: <计算出的签名>
X-Timestamp: 1704067200
X-Nonce: bbcb94189ec932ac4d644da59045eb3c

实现示例#

Python 示例#

JavaScript / Node.js 示例#

Go 示例#

安全注意事项#

时间戳校验#

时间戳使用 Unix 秒级时间戳(不是毫秒)
服务器允许的时间误差为 ±300 秒(5 分钟)
超过容忍度的请求将被拒绝,返回错误码 20009
确保客户端与服务器时钟同步(建议使用 NTP)

Nonce(防重放)#

Nonce 在时间窗口内(300 秒)只能使用一次
推荐使用 UUID 或加密安全的随机字符串
最小长度建议 16 字符以上
Nonce 使用后会在 Redis 中缓存 300 秒

密钥管理#

严格保管 API Secret,绝不在前端或公开仓库泄露
API Secret 仅用于签名计算,不应在请求中传输
定期轮换密钥(Key rotation)
使用安全的密钥存储机制(环境变量、密钥管理服务等)
如果密钥泄露,立即联系技术支持进行轮换

HTTPS#

强制使用 HTTPS 传输所有请求
即使签名正确,HTTP 请求也可能被中间人攻击
验证服务器证书的有效性

错误码(签名相关)#

当签名验证失败时,服务器会返回 HTTP 401 状态码,响应体为 JSON 格式:
{
  "code": 20007,
  "type": "MISSING_SIGNATURE_HEADERS",
  "message": "Missing X-Api-Key header",
  "details": "..."
}
常见签名相关错误码:
代码类型消息描述
20007MISSING_SIGNATURE_HEADERSMissing signature header缺少必要签名头部(X-Api-Key/X-Signature/X-Timestamp)
20008INVALID_TIMESTAMPInvalid timestamp format时间戳格式无效(非数字)
20009TIMESTAMP_EXPIREDRequest timestamp expired时间戳超出容忍范围(±300秒)
20010NONCE_ALREADY_USEDNonce already used非法重放(Nonce 已使用过)
20011INVALID_API_KEYInvalid API keyAPI Key 不存在或已删除
20012INVALID_SIGNATUREInvalid signature签名校验失败
20013INTERNAL_ERRORInternal error服务器内部错误

测试与排查#

排查建议#

1.
检查 JSON 规范化:确保对象键按字母顺序排序,数字和 null 值保持原样
2.
验证 Body Hash:确保 Body Hash 是对规范化后 JSON 字符串的 SHA256 哈希
3.
检查时间戳:确保使用秒级时间戳(不是毫秒),且与服务器时间误差在 ±300 秒内
4.
验证签名字符串:按照 method + path + sortedQuery + timestamp + bodyHash 的顺序拼接
5.
确认必需头部:检查 X-Api-Key、X-Signature、X-Timestamp 是否都已设置
6.
先测试简单请求:从 GET 请求(无 Body)开始测试,逐步增加复杂度

测试向量#

测试用例 1:POST 请求(带 JSON Body)#

输入:
Method: POST
Path: /test
Query: 
Body: {"name":"test","age":25}
Timestamp: 1704067200
Nonce: bbcb94189ec932ac4d644da59045eb3c
API Secret: test-secret
计算过程:
1.
规范化 Body:{"age":25,"name":"test"}
2.
Body Hash (SHA256):c8d3b6a5e4f3a2b1d9c8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6
3.
签名字符串(6个部分,用换行符分隔):
POST
/test

1704067200
c8d3b6a5e4f3a2b1d9c8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6
bbcb94189ec932ac4d644da59045eb3c
4.
Signature:使用 HMAC-SHA256 计算

测试用例 2:GET 请求(带 Query 参数)#

输入:
Method: GET
Path: /test
Query: c=3&a=1&b=2
Body: 
Timestamp: 1704067200
API Secret: test-secret
计算过程:
1.
排序 Query:a=1&b=2&c=3
2.
Body Hash:空字符串
3.
Nonce:bbcb94189ec932ac4d644da59045eb3c
4.
签名字符串(6个部分,用换行符分隔):
GET
/test
a=1&b=2&c=3
1704067200

bbcb94189ec932ac4d644da59045eb3c
5.
Signature:使用 HMAC-SHA256 计算

支持与联络#

若实现过程中遇到问题,请按以下步骤排查并反馈:
1.
核对规范化逻辑:
确认 JSON 对象的键是否按字母顺序排序
确认数字和 null 值是否保持原样(不转换为字符串)
确认数组元素顺序是否保持不变
2.
验证签名计算:
打印出规范化后的 Body
打印出 Body Hash(SHA256)
打印出完整的签名字符串
确认签名字符串的拼接顺序和内容
3.
检查时间同步:
使用 Unix 秒级时间戳(不是毫秒)
确保系统时钟与标准时间同步(NTP)
时间误差应在 ±300 秒内
4.
反馈信息:
如需技术支持,请提供以下信息:
请求方法、路径、Query 参数
原始 Body 和规范化后的 Body
Body Hash 值
时间戳
签名字符串
计算出的签名
完整的错误响应

附录:常见问题#

Q1:时间戳应该使用秒还是毫秒?#

A:使用 Unix 秒级时间戳。例如:1704067200(不是 1704067200000)。

Q2:JSON 中的数字需要转换为字符串吗?#

A:不需要。数字保持原样,例如 {"age":25},不是 {"age":"25"}。

Q3:Nonce 是必需的吗?#

A:是必需的。X-Nonce 头是必选的,服务器会验证其唯一性以防重放攻击。

Q4:Query 参数需要排序吗?#

A:是的。Query 参数必须按 key 的字母顺序排序后再参与签名计算。

Q5:空 Body 如何处理?#

A:如果请求没有 Body(如 GET 请求),Body Hash 使用空字符串 ""。

Q6:签名失败最常见的原因是什么?#

A:最常见的原因包括:
时间戳格式错误(使用了毫秒而不是秒)
JSON 规范化不正确(键未排序、数字被转换为字符串)
Query 参数未排序
签名字符串拼接顺序错误
API Secret 不正确
修改于 2026-05-11 03:22:42
上一页
申请API Key 与 API Secret
下一页
错误码参考
Built with