消息签名和签名验证
为防止中间人攻击,发送者必须对请求和响应消息进行签名,接收者必须验证签名。
ZOLOZ 服务强制性验证每条请求消息的签名,因此商户必须正确对请求进行签名。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 header 字段的请求时间
- 点字符 (".")
- 请求正文
以下是一个商户待签名内容字符串的示例:
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。
输入参数:
输出参数:
SIGNATURE
:最终生成的签名字符串。
4. header 中配置签名
HTTP request header 或者 HTTP response header 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 header 字段的响应时间
- 点字符 (".")
- 响应正文
以下是一个待验证内容字符串的示例:
POST /api/v1/zoloz/authentication/test
2089012345678900.2020-01-01T08:00:01+0800.{
"title": "hello",
"description": "just for demonstration."
}
3. header 中提取签名
HTTP request header 或者 HTTP response header 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 header 中提取签名 提取的签名字符串。PUBLIC_KEY
:步骤 1 获取公钥 获取的公钥。
输出参数:
IS_SIGNATURE_VALID
:布尔值,说明提取的签名是否匹配待验证内容字符串。