方法签名
方法签名用以防止方法被滥用、被中间商窃取信息和篡改,以及防止CSRF攻击。
注意:
如果您在WEB上使用,我们有更简单的验证方法,请参见WEB验证方法
WEB验证方法有一定的局限性和安全性问题,如果有可能,请尽量使用普通签名方式
准备工作
您需要获得
AccessKeyId
和AccessKeySecret
。 请妥善保存AccessKeySecret
。阅读RFC文档 RFC 2104 了解HMAC-SHA1加密方法
阅读RFC文档 RFC 2616 了解请求body 的MD5值算法
熟悉您使用的请求库
加密方法
签名生成
Authorization = "Qingzhen " + AccessKeyId + ":" + Signature
Signature = Base64(hmac-sha1(AccessKeySecret,
METHOD
+ Date
+ CanonicalizedHeaders
+ CanonicalizedResource
)
)
注意: Qingzhen 后有一个半角空格
Authorization 字段说明
字段 | 类型 | 默认值 | 必填 | 说明 | 备注 |
---|---|---|---|---|---|
AccessKeyId | string | 是 | 访问用的key | 需要向我们索取 | |
Signature | string | 是 | 计算出的加密密钥 | 参阅下面的说明 |
Signature 所需字段说明
字段 | 类型 | 必填 | 大小写 | 说明 | 备注 |
---|---|---|---|---|---|
AccessKeySecret | string | 是 | 小写 | 加密secret | 向我们获取 |
METHOD | string | 是 | 大写 | 请求方法 | 大写,如POST |
Date | long | 是 | 数字 | 是 | 1970-01-01到现在的毫秒数 |
CanonicalizedHeaders | string | 是 | header小写,内容不变更 | 请求的特殊Header,一般就是content-md5和header | 多个参数请直接拼接,参数名冒号后面有空格,参数名小写。 |
CanonicalizedResource | string | 是 | 不变更 | 请求的URL,不含Host | 根据SortFlag拼接的url |
注意:
CanonicalizedHeaders 字段名小写,值按照实际情况来(因为HTTP/2规范要求全小写)
header必须升序排列,我们发现部分请求库会重新排布request header
canonicalizedResource 请注意部分库会自动将URL中参数进行URLEncode以及调换位置。我们建议您自行URLEncode参数请求
请求头应该类似于
authorization: QINGZHEN " + AccessKeyId + ":" + Signature
content-md5: xxxxxxx
qingzhen-token: xxxxxxx
user-timestamp: 1548179660299
没有body的时候,可以不发送Content-MD5。
token可在URL中携带,与v1不同,为了避免歧义,token不再允许在请求的body中存在
范例
准备发送数据
- 我们准备以post json
{"accessKeySecret":"张宝华"}
到/v2/system/sign?papaya=ee
- 假设token为
2223323
- 假设AccessKeyId 为
dingding
- 假设AccessKeySecret 为
张宝华
- JSON文件内容
{"accessKeySecret":"张宝华"}
- 以
UTF8
编码 计算content MD5, 然后Base64
Base64(MD5(byte('{"accessKeySecret":"张宝华"}'))) = 'CprM/TvhcReejHlhO4jvVg=='
计算示范:
import base64
import hashlib
source='{"accessKeySecret":"张宝华"}'
hash = hashlib.md5(source.encode(encoding='UTF-8'))
b64bytes = base64.b64encode(hash.digest())
content_md5 = b64bytes.decode(encoding='UTF-8',errors='strict')
import java.security.*;
import java.util.Base64;
class Untitled {
public static void main(String[] args) throws Exception{
String source = "{\"accessKeySecret\":\"张宝华\"}";
byte[] bytesOfMessage = source.getBytes("UTF-8");
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] thedigest = md.digest(bytesOfMessage);
String encodedString = Base64.getEncoder().encodeToString(thedigest);
System.out.println(encodedString);
}
}
使用 POST 方法, method 为
POST
取当前时间的毫秒数,转成string,为
1548179660299
因为要发送 content MD5和token 的header,构造 canonicalizedHeaders为
content-md5: CprM/TvhcReejHlhO4jvVg==qingzhen-token: 2223323user-timestamp: 1548179660299
- 注意,如果没有内容可以不发送Content-MD5,一旦发送,即使为空 也要计算空字符串的MD5
- 因为要发送到URL,构造 canonicalizedResource
/v2/system/sign?papaya=ee
- 拼接验证字符串
POST1548179660299content-md5: CprM/TvhcReejHlhO4jvVg==qingzhen-token: 2223323user-timestamp: 1548179660299/v2/system/sign?papaya=ee
- 用 accessKeySecret
张宝华
进行签名,再Base64
signature = Base64(hmacSHA1String('POST1548179660299content-md5: CprM/TvhcReejHlhO4jvVg==qingzhen-token: 2223323user-timestamp: 1548179660299/v2/system/sign?papaya=ee','张宝华'))
signature = 'Fn32tNf7dFl1XKlkGDuxdc2xRlw='
- 构造
Authorization
头
Authorization = "Qingzhen " + AccessKeyId + signature
Authorization: Qingzhen dingding:Hce1owpfR5XpdjpAdow39YYmi28=:1548176312517
为请求添加header
Content-MD5: CprM/TvhcReejHlhO4jvVg==
Authorization: Qingzhen dingding:Fn32tNf7dFl1XKlkGDuxdc2xRlw=
Token: 2223323
发送请求
POST /v2/system/sign?papaya=ee HTTP/1.1
Host: localhost:1926
Content-MD5: CprM/TvhcReejHlhO4jvVg==
Authorization: Qingzhen dingding:Fn32tNf7dFl1XKlkGDuxdc2xRlw=
Qingzhen-Token: 2223323
Content-Type: application/json
User-Timestamp: 1548179660299
cache-control: no-cache
Qingzhen-AutoMock-Token: 12fa9d26-e93b-4760-8b80-f1f266c6a375
{"accessKeySecret":"张宝华"}------WebKitFormBoundary7MA4YWxkTrZu0gW--
您可以将请求发往 /v2/system/sign 用以验证您的签名是否正确。
例子2:发送不带body,不校验content-md5的请求(GET)
- 我们准备 GET
/v2/system/sign?papaya=ee
- 假设token为
2223323
- 假设AccessKeyId 为
dingding
- 假设AccessKeySecret 为
张宝华
取当前时间的毫秒数,转成string,为
1548229232957
使用 GET 方法, method 为
GET
构造
canonicalizedHeaders
为
qingzhen-token: 2223323user-timestamp: 1548229232957
- 构造 canonicalizedResource
/v2/system/sign?papaya=ee
- 拼接验证字符串
GET1548229232957qingzhen-token: 2223323user-timestamp: 1548229232957/v2/system/sign?papaya=ee
- 签名
signature = Base64(hmacSHA1String('GET1548229232957qingzhen-token: 2223323user-timestamp: 1548229232957/v2/system/sign?papaya=ee','张宝华'))
signature = 'pamKj/LW62TtWn6q6lnQ1z8EahI='
- 添加Header,请求
GET /v2/system/sign?papaya=ee HTTP/1.1
Host: localhost:1926
Authorization: Qingzhen dingding:pamKj/LW62TtWn6q6lnQ1z8EahI=
Qingzhen-Token: 2223323
Content-Type: application/json
User-Timestamp: 1548229232957
cache-control: no-cache