报文签名和签名验证
为了防止中间人攻击,报文发送者必须对请求和响应报文进行签名,报文接收者必须验证签名。
ZOLOZ服务强制验证每条请求报文的签名,因此商户必须正确对请求进行签名。ZOLOZ服务同时也对响应报文进行签名,但商户可以自行决定是否验证响应报文的签名。为了安全起见,强烈建议商户验证所有的响应报文签名。
报文签名
报文签名流程
下图展示了从商户角度如何进行请求报文签名,以及从ZOLOZ服务角度如何进行响应报文签名。
图1. 报文签名活动图
报文签名步骤
1. 获取私钥
对报文进行签名必须使用私钥。
- 对于请求报文,商户端必须生成一个RSA 2048密钥对。生成的密钥对包含一个私钥,商户可以使用该私钥对请求报文进行签名。
- 对于响应报文,在创建商户账号时ZOLOZ系统会生成一个RSA 2048密钥对。每个商户的密钥对都是唯一的,且包含一个私钥,ZOLOZ服务可以使用该私钥对响应报文进行签名。
2. 构建待签名内容
待签名内容是由若干元素组成的字符串,请求报文和响应报文对应的待签名内容不同。
请求报文
商户待签名内容字符串构建格式如下:
<Request Method> <Request URI>
<Client ID>.<Request Time>.<Request Body>
构建待签名内容字符串须按以下顺序连接各元素字符串:
- 请求方法
- 空格符 (" ")
- 请求URI
- 换行符 ("\n")
- 客户端ID
- 点字符 (".")
- 设置Request-Time字段的请求时间
- 点字符 (".")
- 请求正文
以下是一个商户待签名内容字符串的示例:
POST /api/v1/zoloz/authentication/test
2089012345678900.2020-01-01T08:00:00+0800.{
"title": "hello",
"description": "just for demonstration."
}
响应报文
ZOLOZ服务待签名内容字符串与商户待验证内容字符串相同。更多信息,请参见本文中的构建待验证内容(响应报文)。
3. 计算签名
计算签名公式:
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
字段中指定生成的签名字符串。格式如下:
Signature: algorithm=RSA256, signature=<SIGNATURE>
签名验证
签名验证流程
下图展示了从ZOLOZ服务角度如何进行请求报文的签名验证,以及从商户角度如何进行响应报文的签名验证。
图2. 签名验证活动图
签名验证步骤
1. 获取公钥
验证签名必须使用公钥。
- 对于请求报文,ZOLOZ服务使用的公钥来自商户生成的RSA 2048密钥对。在发送任何请求之前,必须先在ZOLOZ系统中注册公钥。ZOLOZ服务可以使用已注册的公钥来验证商户发送的每个请求签名。
- 对于响应报文,商户必须获得ZOLOZ服务提供的公钥。商户创建账号时,ZOLOZ系统会生成一个RSA 2048密钥对,生成的密钥对包含一个公钥。商户可以使用该公钥验证从ZOLOZ返回的每个响应签名。
在ZOLOZ系统中注册请求公钥或从ZOLOZ系统获取响应公钥的更多信息,请参见获取API凭证。
2. 构建待验证内容
待验证内容是由若干元素组成的字符串,请求报文和响应报文对应的待验证内容不同。
请求报文
ZOLOZ服务待验证内容字符串与商户签名内容字符串相同。更多信息,请参见本文中的构建待签名内容 (请求报文)。
响应报文
商户待验证内容字符串构建格式如下:
<Request Method> <Request URI>
<Client ID>.<Response Time>.<Response Body>
构建待验证内容字符串须按以下顺序连接各元素字符串:
- 请求方法
- 空格符 (" ")
- 请求URI
- 换行符 ("\n")
- 客户端ID
- 点字符 (".")
- 设置Response-Time字段的响应时间
- 点字符 (".")
- 响应正文
以下是一个待验证内容字符串的示例:
POST /api/v1/zoloz/authentication/test
2089012345678900.2020-01-01T08:00:01+0800.{
"title": "hello",
"description": "just for demonstration."
}
3. 从header中提取签名
从HTTP请求头或HTTP响应头的Signature
字段中提取签名。
Signature: algorithm=RSA256, signature=<SIGNATURE_TO_BE_EXTRACTED>
4. 验证签名
检查提取的签名是否与待验证内容字符串匹配的公式:
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
:布尔值,用于说明提取的签名与待验证内容字符串是否匹配。