报文签名和签名验证

为了防止中间人攻击,报文发送者必须对请求和响应报文进行签名,报文接收者必须验证签名。

ZOLOZ服务强制验证每条请求报文的签名,因此商户必须正确对请求进行签名。ZOLOZ服务同时也对响应报文进行签名,但商户可以自行决定是否验证响应报文的签名。为了安全起见,强烈建议商户验证所有的响应报文签名。

报文签名

报文签名流程

下图展示了从商户角度如何进行请求报文签名,以及从ZOLOZ服务角度如何进行响应报文签名。

消息签名活动图.png

图1. 报文签名活动图

报文签名步骤

1. 获取私钥

对报文进行签名必须使用私钥。

  • 对于请求报文,商户端必须生成一个RSA 2048密钥对。生成的密钥对包含一个私钥,商户可以使用该私钥对请求报文进行签名。
  • 对于响应报文,在创建商户账号时ZOLOZ系统会生成一个RSA 2048密钥对。每个商户的密钥对都是唯一的,且包含一个私钥,ZOLOZ服务可以使用该私钥对响应报文进行签名。

2. 构建待签名内容

待签名内容是由若干元素组成的字符串,请求报文和响应报文对应的待签名内容不同。

请求报文

商户待签名内容字符串构建格式如下:

copy
<Request Method> <Request URI>
<Client ID>.<Request Time>.<Request Body>

构建待签名内容字符串须按以下顺序连接各元素字符串:

  1. 请求方法
  2. 空格符 (" ")
  3. 请求URI
  4. 换行符 ("\n")
  5. 客户端ID
  6. 点字符 (".")
  7. 设置Request-Time字段的请求时间
  8. 点字符 (".")
  9. 请求正文

以下是一个商户待签名内容字符串的示例:

copy
POST /api/v1/zoloz/authentication/test
2089012345678900.2020-01-01T08:00:00+0800.{
  "title": "hello",
  "description": "just for demonstration."
}

响应报文

ZOLOZ服务待签名内容字符串与商户待验证内容字符串相同。更多信息,请参见本文中的构建待验证内容(响应报文)

3. 计算签名

计算签名公式:

copy
SIGNATURE=base64urlsafe_encode(sha256withrsa_sign($CONTENT_TO_BE_SIGNED, $PRIVATE_KEY))

计算签名公式由以下几部分组成:

  • 依赖的函数
    • sha256withrsa_sign:该函数为提供的内容生成数字签名。更多信息,请参见sha256withrsa_sign
    • base64urlsafe_encode:该函数为生成的数字签名进行编码。更多信息,请参见base64urlsafe_encode
  • 输入参数
    • CONTENT_TO_BE_SIGNED步骤2中构建的待签名内容字符串。
    • PRIVATE_KEY步骤1中生成的私钥。
  • 输出参数
    • SIGNATURE:最终生成的签名字符串。

4. 在header中配置签名

在HTTP请求头或HTTP响应头的Signature字段中指定生成的签名字符串。格式如下:

copy
Signature: algorithm=RSA256, signature=<SIGNATURE>

签名验证

签名验证流程

下图展示了从ZOLOZ服务角度如何进行请求报文的签名验证,以及从商户角度如何进行响应报文的签名验证。

签名验证活动图.png

图2. 签名验证活动图

签名验证步骤

1. 获取公钥

验证签名必须使用公钥。

  • 对于请求报文,ZOLOZ服务使用的公钥来自商户生成的RSA 2048密钥对。在发送任何请求之前,必须先在ZOLOZ系统中注册公钥。ZOLOZ服务可以使用已注册的公钥来验证商户发送的每个请求签名。
  • 对于响应报文,商户必须获得ZOLOZ服务提供的公钥。商户创建账号时,ZOLOZ系统会生成一个RSA 2048密钥对,生成的密钥对包含一个公钥。商户可以使用该公钥验证从ZOLOZ返回的每个响应签名。

在ZOLOZ系统中注册请求公钥或从ZOLOZ系统获取响应公钥的更多信息,请参见获取API凭证

2. 构建待验证内容

待验证内容是由若干元素组成的字符串,请求报文和响应报文对应的待验证内容不同。

请求报文

ZOLOZ服务待验证内容字符串与商户签名内容字符串相同。更多信息,请参见本文中的构建待签名内容 (请求报文)

响应报文

商户待验证内容字符串构建格式如下:

copy
<Request Method> <Request URI>
<Client ID>.<Response Time>.<Response Body>

构建待验证内容字符串须按以下顺序连接各元素字符串:

  1. 请求方法
  2. 空格符 (" ")
  3. 请求URI
  4. 换行符 ("\n")
  5. 客户端ID
  6. 点字符 (".")
  7. 置Response-Time字段的响应时间
  8. 点字符 (".")
  9. 响应正文

以下是一个待验证内容字符串的示例:

copy
POST /api/v1/zoloz/authentication/test
2089012345678900.2020-01-01T08:00:01+0800.{
  "title": "hello",
  "description": "just for demonstration."
}

3. 从header中提取签名

从HTTP请求头或HTTP响应头的Signature字段中提取签名。

copy
Signature: algorithm=RSA256, signature=<SIGNATURE_TO_BE_EXTRACTED>

4. 验证签名

检查提取的签名是否与待验证内容字符串匹配的公式:

copy
IS_SIGNATURE_VALID=sha256withrsa_verify($CONTENT_TO_BE_VALIDATED, base64urlsafe_decode($SIGNATURE), $PUBLIC_KEY))

验证签名公式由以下几部分组成:

  • 依赖的函数
    • base64urlsafe_decode:该函数用于解码步骤3中提取的签名。更多信息,请参见base64urlsafe_decode
    • sha256withrsa_verify:该函数用于验证签名。更多信息,请参见sha256withrsa_verify
  • 输入参数
    • CONTENT_TO_BE_VALIDATED:步骤2中构建的待验证内容字符串。
    • SIGNATURE步骤3中提取的签名字符串。
    • PUBLIC_KEY步骤1中获取的公钥。
  • 输出参数
    • IS_SIGNATURE_VALID:布尔值,用于说明提取的签名与待验证内容字符串是否匹配。