跳到主要内容

签名算法

游戏服务端和世游服务端之间的网络通信,均需要使用以下的 SEAYOO-HMAC-SHA256 签名算法进行签名及验证。

前置准备

游戏已经从世游侧获取到了 Game IDSecret Key。这些是本签名算法必须使用的两个值。

原语 Function

以下是计算签名过程中会用到的原语 function。

这些原语 function 在各个编程语言中通常都有标准库提供其功能。

FunctionDescription
Hex()Lowercase base 16 encoding.
See https://en.wikipedia.org/wiki/Hexadecimal
SHA256Hash()Secure Hash Algorithm (SHA) cryptographic hash function 256-bit.
See https://en.wikipedia.org/wiki/SHA-2
HMAC-SHA256()Computes HMAC by using the SHA256 algorithm with the signing key provided.
See https://en.wikipedia.org/wiki/HMAC

生成签名

步骤一: 构造待签名的 StringToSign

待签名的字符串 StringToSign 是包含以下由换行符 \n 分隔的结构。换行符 \n 的 ASCII 值为 0x0A

SEAYOO-HMAC-SHA256\n
<HTTPMethod>\n
<RequestURI>\n
<Timestamp>\n
<HashedPayload>

HTTPMethod 是 HTTP 方法,例如 GET, POST

RequestURI 是 HTTP 请求中的 URI 部分,不包含协议与域名,如果有 Query String 的话需要包含。示例:

/v1/server/create-order
/foo/bar?prefix=somePrefix&marker=someMarker&max-keys=2

Timestamp 是发起 HTTP 请求时的系统秒级时间戳,使用 UTC 时区的 ISO 8601 格式。示例:

20231117T082149Z

HashedPayload 是对 HTTP request bodypayload 哈希后的结果。计算的方式是:

Hex(SHA256Hash(<payload>)

如果 HTTP request 中的 body 为空,例如 GET request,则 payload 为空字符串,此时计算哈希的方式为:

Hex(SHA256Hash(""))

在这种情况下,空字符串的哈希结果固定为:

e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

步骤二:计算签名

使用分配给游戏的 Secret Key 作为 SigningKey,对步骤一构造出的 StringToSign 计算 HMAC-SHA256 值:

Hex(HMAC-SHA256(SigningKey, StringToSign))

计算出的签名结果示例:

152e1330eb67c094a3ca93a8e713eb136c24227225cd61901fbb1df0b4e4f56f

步骤三:将签名添加至请求

为 HTTP 请求添加以下 Authorization header:

Authorization: <Scheme> Game=<Game>, Timestamp=<Timestamp>, Signature=<Signature>
  • Scheme 固定为 SEAYOO-HMAC-SHA256
  • Game 为分配给游戏的 Game ID,原样填在这里
  • Timestamp 为步骤一中发起 HTTP 请求时的系统秒级时间戳,原样填在这里
  • Signature 为步骤二中计算出的签名,原样填在这里

示例:

Authorization: SEAYOO-HMAC-SHA256 Game=catsnsoup, Timestamp=20231117T082149Z, Signature=adefae80e1239c6bfd91181f5139441539e21d1f6d947c2822c3ef3afa5d4f95

完整示例

假定输入数据如下:

  • Gamexcom
  • SigningKeysk_secret
  • HTTPMethodPOST
  • HTTP URL 为 https://api.example.com/v1/my-test-api?key=123&value=foobar
  • HTTP Request Body 为 {"hello":"world"}
  • 签名时的时间戳 Timestamp20231228T065821Z

则签名过程中的示例如下:

  1. HTTP URL 对应的 RequestURI 为:
/v1/my-test-api?key=123&value=foobar
  1. HTTP Request Body 对应的 HashedPayload 为:
93a23971a914e5eacbf0a8d25154cda309c3c1c72fbb9914d47c60f3cb681588
  1. 待签名的字符串 StringToSign 为:
SEAYOO-HMAC-SHA256
POST
/v1/my-test-api?key=123&value=foobar
20231228T065821Z
93a23971a914e5eacbf0a8d25154cda309c3c1c72fbb9914d47c60f3cb681588
  1. 计算出的签名结果 Signature 为:
05f5be3e9f55f8fa2fb027666ec5bb379ff4732181839c28c77662b7e8eb0fea
  1. 为 HTTP 请求添加的 Authorization header 为:
Authorization: SEAYOO-HMAC-SHA256 Game=xcom, Timestamp=20231228T065821Z, Signature=05f5be3e9f55f8fa2fb027666ec5bb379ff4732181839c28c77662b7e8eb0fea

验证签名

  1. 从 HTTP Request 中提取出 Authorization header,并解析出 SchemeGameTimestampSignature。如果不能正确解析出上述值则拒绝请求,否则进行下一步。
  2. 验证 Scheme。如果不等于 SEAYOO-HMAC-SHA256 则拒绝请求,否则进行下一步。
  3. 验证 Timestamp。如果和服务器当前系统时间的差异在 5 分钟以上则拒绝请求,否则进行下一步。
  4. 验证 GameGame 与 Secret Key 是固定且已知的。如果 Game 不一致则拒绝请求,否则进行下一步。
  5. 验证 Signature
    1. 解析 HTTP Request,按照生成签名的步骤一,构造出待签名的 StringToSign
    2. 使用 Secret Key 作为 SigningKey,按照生成签名的步骤二,对 StringToSign 进行签名计算,得到 Signature
    3. 对比 SignatureSignature,如果匹配,则签名验证通过,继续执行业务逻辑,否则应当拒绝请求。