基本规范
签名的目的
【来自百度百科】数字签名(又称公钥数字签名、电子签章)是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法。一套数字签名通常定义两种互补的运算,一个用于签名,另一个用于验证。
数字签名,就是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。
【来自百度百科】数字签名是非对称密钥加密技术与数字摘要技术的应用。
通俗来讲,签名的目的主要有以下三点:
- 请求参数是否被篡改;
- 请求来源是否合法;
- 请求是否具有唯一性。
来伊份openAPi签名规范
签名过程中的X-Co-Client和SecretKey由来伊份提供,测试环境和生产环境提供不同的值。
请求头字段
参数名字 | 参数类型 | 是否必须 | 说明 |
---|---|---|---|
X-Co-Client | String | 是 | 商户Id(来伊份提供) |
X-Co-Sign | String | 是 | 签名 |
X-Co-TimeStamp | String | 是 | 签名时间戳 |
Content-Type | String | 是 | 内容类型(默认填:application/json;charset=UTF-8) |
签名规则
- 说明
公式:$sign = base64(hmac-sha1(SecretKey, HTTPRequestMethod + "\n" + CanonicalURI + "\n" + CanonicalQueryString + "\n" + CanonicalHeaders + "\n" + md5(CanonicalBody))) 以上公式中“\n”为换行符,参与签名的有HTTPRequestMethod 、CanonicalURI 、CanonicalQueryString 、CanonicalHeaders 、CanonicalBody五个部分,任何一个部分为空时,如CanonicalQueryString或者CanonicalBody,该部分不参与签名,也不需要用空字符串代替。
- SecretKey表示签名所需的密钥,服务端存储不传递;
- HTTPRequestMethod表示HTTP 请求的Method,主要有GET,POST,PUT,DELETE,HEAD,OPTION等,使用大写;
- CanonicalURI表示格式化后的请求URI= path,path使用/开头(即使后面为空)。例子:/shop/v1/goods/9642;
- CanonicalQueryString表示格式化后的请求参数字符串,可为空。对请求参数按照key的字典序排列后,进行以下拼接CanonicalQueryString = (key1=urlEncode(val1)&key2=urlEncode(val2)...),urlEncode指遵循RFC 3986的URL Encode。
- CanonicalHeaders表示格式化后的Headers,使用X-Co-Client和X-Co-TimeStamp, lower表示转换为小写,trim表示去除前后空格。 CanonicalHeaders = lower("X-Co-Client") + ':' + trim(HeaderValue) + "\n" + lower("X-Co-TimeStamp") + ':' + trim(HeaderValue)
- CanonicalBody表示格式后的Body,可为空。API的Body都是Json,考虑对json进行md5计算以减少传输数据量,MD5可以直接参考在线加密工具:https://www.sojson.com/encrypt_md5.html。
- 注意
- 上述MD5和hmac-sha1算法中,空格、换行等都进行加密,所以在进行加密的时候不要替换空格换行符等。
- body字符采用32位MD5加密,并转成大写字母。
- hmac-sha1加密之后为字节类型,不要转成字符串类型。
- uri参数的值当中携带有空格,例:ex=AA BB CC,在h5端或IOS端可能会出现urlencod后空格转换成"%20",例:ex=AA%20BB%20CC,这时候请对“%20”替换成“+“再进行签名操作,转换后:ex=AA+BB+CC
示例
参数
RequestMethod | POST |
---|---|
URL | /lyf-bean/api/ycard/info/postMerIntegral?ut=12345&plateform=3&character=签名过程 |
X-Co-Client | 6E9B64AD979440FFBC11A410D8D74712 |
Secret | SECRETKEY-E180922C2EB64DEEA5A3CE |
X-Co-TimeStamp | 1539843173902 |
body | {"id":12345,"userName":"xiaoming","age":18} |
流程
- 对body进行MD5,如果body为空则不需要,以上body进行MD5的结果是:AD36DE180AC4817F8D50ABCDFFD54AD7
- 分离requestURl,分为requestURI和requestParameter requestURI:/lyf-bean/api/ycard/info/postMerIntegral requestParameter:ut=12345&plateform=3&character=签名过程 并对requestParameter按照key的字母顺序进行排序【对value进行URLEncod,key、value之前用”=”连接,每组之间还是用“&”连接】,排序后的结果是:character=%E7%AD%BE%E5%90%8D%E8%BF%87%E7%A8%8B&plateform=3&ut=12345
- 组合requsetHeader:对header进行组合【key、value中间使用“:”连接,每组之间用“\n”连接】,结果是: x-co-client:6E9B64AD979440FFBC11A410D8D74712 x-co-timestamp:1539843173902
- 最后进行SHA加密的字段如下:
RequestMethod | POST |
---|---|
CanonicalURI | /lyf-bean/api/ycard/info/postMerIntegral |
CanonicalQueryString | character=%E7%AD%BE%E5%90%8D%E8%BF%87%E7%A8%8B&plateform=3&ut=12345 |
CanonicalHeaders | x-co-client:6E9B64AD979440FFBC11A410D8D74712 x-co-timestamp:1539843173902 |
md5(CanonicalBody) | AD36DE180AC4817F8D50ABCDFFD54AD7 |
- 把以上5个字段按从上到下的顺序用“\n”连接之后的字符串是:
POST
/lyf-bean/api/ycard/info/postMerIntegral
character=%E7%AD%BE%E5%90%8D%E8%BF%87%E7%A8%8B&plateform=3&ut=12345
x-co-client:6E9B64AD979440FFBC11A410D8D74712
x-co-timestamp:1539843173902
AD36DE180AC4817F8D50ABCDFFD54AD7
- 对以上的字符串进行SHA加密,然后进行Base64,得出的结果:YYRrr5BEE/gixiKGr8RXYdXFV5I=
Sha加密的结果是byte类型,不要转字符串
每行使用 \n 分隔
第一行:method,如:GET,POST等。需大写
第二行:path,如:/lyf-bean/api/ycard/info/postMerIntegral
第三行:queryString,对所有参数的key进行排序 ,采用key=value格式,多个请用&拼接,value需要进行URLEncoder,如:test=123&test1=321。注意:数据可空,也不要使用 \n 分隔
第四行:clientId,商户号,拼接成 x-co-client:{clientId},x-co-client保持小写 。
第五行:timestamp,时间戳,拼接成 x-co-timestamp:{timestamp},x-co-timestamp保持小写 。
第六行:bodyMD5,消息体使用MD5签名
常见问题
- header里的content-type需传入application/json或者application/json;charset=UTF-8;
- clientId、密钥字符串有空格、回车符;
- 签名的时间戳和传递的签名戳不一样;
- body使用了md5之后的结果;正确的做法是body按照正常的数据传输即可,调用openapi网关只是额外在header里增加了三个字段;
- 签名使用的字段名称错误,比如x-co-client写成x_co_client;
- uri参数的空格没有转换成“+“