签名机制
为保证 HTTP/HTTPS 服务的安全使用,在服务配置中可选择开启签名计算,在调用 API 时全局服务会对开启签名的服务进行签名计算,并将签名放到请求header中。本文介绍计算签名的方法和示例。
步骤一:构造规范化请求字符串
1、CanonicalizedHeaderString:
(1)header参数范围:包括header中以“x-dmpaas”开头的系统参数、header自定义参数,不包括header参数中的x-dmpaas-signature参数。
(2)header参数排序和拼接:
按照参数字符串字典升序对header参数排序,多个header之间用&连接。
使用等号(=)连接编码后的header参数和编码后的header参数值,编码方式参考附录。
示例:
Headers:
自定义参数
test-header1=test-header-value1
test-header2=test-header-value2
系统参数:
x-dmpaas-accesskey=testkey
x-dmpaas-beebot-chat-id=beebot-chat-id-value
x-dmpaas-signature-nonce=d990cdec-3b2c-4235-a836-704f3a4dfa18
x-dmpaas-timestamp=2022-12-08T14:11:16Z
结果:
CanonicalizedHeaderString字符串是test-header1=test-header-value1&test-header2=test-header-value2&x-dmpaas-accesskey=testkey&x-dmpaas-beebot-chat-id=beebot-chat-id-value&x-dmpaas-signature-nonce=d990cdec-3b2c-4235-a836-704f3a4dfa18&x-dmpaas-timestamp=2022-12-08T14%3A11%3A16Z
2、CanonicalizedQueryString:
(1)query参数范围:全局服务页面上所有query参数、URL连接串提前预置的query参数。
(2)query参数排序和拼接:
使用等号(=)连接编码后的query参数和编码后的query参数值,编码方式参考附录。
按照参数字符串字典升序对query参数排序,多个query之间用&连接。
示例:
Querys :
key1=value1
key2=value2
CanonicalizedQueryString字符串是key1=value1&key2=value2
3、CanonicalizedBodyString:请求的body 字符串,如果没有body,就用空字符串("");
步骤二:构造签名字符串
我们以 Java 为例,该字符串构造规则如下:
String stringToSign =
HTTPMethod + "&" +
encodeURIComponent("/") + "&" +
encodeURIComponent(CanonicalizedHeaderString) + "&" +
encodeURIComponent(CanonicalizedQueryString) + "&" +
encodeURIComponent(CanonicalizedBodyString)
备注:
HTTPMethod:发送请求的 HTTP 方法,例如 POST
encodeURIComponent编码方法是指:使用 UTF-8 字符集按照RFC3986规则(https://www.rfc-editor.org/rfc/rfc3986?spm=a2c4g.11186623.0.0.549927b5NRn8tS#page-28)编码请求参数和参数值进行URLEncode,编码具体规则请参看“附录:参数编码方式”。
步骤三:计算签名
在全局服务配置中可查到AccessKey匹配的AccessToken,作为加密的密钥,使用 HMAC-SHA1 的签名算法,计算待签名字符串StringToSign的签名。以 Java 为例,计算方法如下:
String signature = Base64(HMAC_SHA1(accessToken + "&", stringToSign))
现在您得到了公共参数 Signature 的签名值 signature。然后和请求header中x-dmpaas-signature的值进行对比。
签名示例
模拟请求配置
HTTPMethod: POST;
Headers:
自定义参数
test-header1=test-header-value1
test-header2=test-header-value2
系统参数:
x-dmpaas-accesskey=testkey
x-dmpaas-beebot-chat-id=beebot-chat-id-value
x-dmpaas-signature-nonce=d990cdec-3b2c-4235-a836-704f3a4dfa18
x-dmpaas-timestamp=2022-12-08T14:11:16Z
Querys:
key1=value1
key2=value2
Body:
{"test-body-key1":"test-body-value1","test-body-key2":"test-body-value2"}
假设您获得了AccessKey=testkey 以及 AccessToken=testtoken,签名流程如下:
步骤一:构造规范化请求字符串
CanonicalizedHeaderString:test-header1=test-header-value1&test-header2=test-header-value2&x-dmpaas-accesskey=testkey&x-dmpaas-beebot-chat-id=beebot-chat-id-value&x-dmpaas-signature-nonce=d990cdec-3b2c-4235-a836-704f3a4dfa18&x-dmpaas-timestamp=2022-12-08T14%3A11%3A16Z
CanonicalizedQueryString:key1=value1&key2=value2
CanonicalizedBodyString:{"test-body-key1":"test-body-value1","test-body-key2":"test-body-value2"}
步骤二:构造待签名字符串stringToSign
POST&%2F&test-header1%3Dtest-header-value1%26test-header2%3Dtest-header-value2%26x-dmpaas-accesskey%3Dtestkey%26x-dmpaas-beebot-chat-id%3Dbeebot-chat-id-value%26x-dmpaas-signature-nonce%3Dd990cdec-3b2c-4235-a836-704f3a4dfa18%26x-dmpaas-timestamp%3D2022-12-08T14%253A11%253A16Z&key1%3Dvalue1%26key2%3Dvalue2&%7B%22test-body-key1%22%3A%22test-body-value1%22%2C%22test-body-key2%22%3A%22test-body-value2%22%7D
步骤三:计算签名
计算签名值。例如 AccessToken=testtoken,用于计算的 Key 为testtoken&(注意:加上后缀&)。计算得到的签名值为jpvM83XOLhJ1lHTQR2boROe****=。本示例使用的是 Java Base64 编码方法。
String Signature = Base64(HMAC_SHA1(AccessSecret + "&",stringToSign))
最后您可以比较请求header中的x-dmpaas-signature的值,来进行签名校验。
附录
参数编码方式
在全局服务-HTTP/HTTPS服务调用中,我们需要对请求参数和请求值,使用 UTF-8 字符集按照RFC3986规则进行编码。具体编码规则如下:
字符 A~Z、a~z、0~9 以及字符-、_、.、~不编码。
对其他 ASCII 码字符进行编码。编码格式为%加上16进制的 ASCII 码。例如半角双引号(")将被编码为 %22。
非 ASCII 码通过 UTF-8 编码。
空格编码成%20,而不是加号(+)。
以Java为例:
java.net.URLEncoder.encode(str, "UTF-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~")
为方便表述,我们将此步骤的编码方法,命名为 encodeURIComponent。