接口签名 - 一个实践过的方案(一)

一、签名认证流程

1.1 准备

客户端在调用服务端接口API之前,需要拿到已经授权给自己的账户密钥对:

  • APP Key
  • APP Secret

1.2 客户端生成签名

客户端生成签名步骤:

1、从要发送的HTTP请求中提取关键数据,得到一个用来签名的字符串。

2、使用加密算法加上APP Secret对上一步的字符串进行加密处理,得到签名。

3、将签名等信息放入到Header中,得到最终要发送的HTTP请求。

1.3 客户端生成签名

服务端验证签名步骤:

1、从接收的HTTP请求中提取关键数据,得到一个用来签名的字符串。

2、从请求中读取到APP Key,进而能知道客户端的APP Secret。

3、使用加密算法加上APP Secret对关键数据签名串进行加密处理,得到签名。

4、从接收的请求中读取到签名,对比两个签名是否一致。

二、签名认证详细步骤

2.1 签名串构成

客户端从要发送的HTTP请求中提取出关键数据,组成一个待签名的字符串,由下面五个部分组成:

  1. http method  
  2. url path
  3. headers
  4. content md5
  5. query parameters

以上五个部分之间使用“\n”间隔,如有部分的内容为空则不需要保留“\n”, 字符串内容大小写敏感。

2.1.1 http method

获取请求的http方法,全部大写,比如 “GET”、“POST” 等。

2.1.2 url path

请求url的path部分,不包括host和query参数部分,比如 “/path/data”。

2.1.3 headers

选取请求头:

哪些请求头信息参与到签名,由Header是 tw-signature-headers 的内容决定。参与到签名的header的key的集合,使用英文逗号分割放到 key为  tw-signature-headers 的 Header中,客户端与服务端根据这个值进行选取并拼接签名串。

例如:

tw-signature-headers: tw-appkey,tw-signature-method,tw-nonce,tw-timastamp

可以选取的header列表如下,一共四个:

  • tw-appkey:分配给客户端的账户名
  • tw-nonce:客户端生成的随机字符串,用于防止重放攻击
  • tw-timestamp:时间戳,精确到毫秒,用于防止重放攻击
  • tw-signature-method:签名方法,支持 HmacSHA256、HmacSHA1

拼接请求头:

  1. 将参与签名计算的header的key转为全小写
  2. 将这些header的value值内容去掉开头结尾的空白字符
  3. 将header的key按照字典序排序后,拼接为key:value形式
  4. 将上述所有key:value形式的字符串用“\n”连接
K1 + ":" + V1 + "\n" + K2+ ":" + V2 + "\n"  + ... + Kn + ":" + Vn

注意:

  • 如果一个header的value为空,则使用 key+":" 参与签名,即需要保留key和英文冒号部分。
  • 如果设置了 tw-signature-method 参与签名,但是http实际请求没传值或者值错误,默认采用HmacSHA256参与签名。
  • 如果 tw-signature-headers内容为空,则header部分不参与签名计算。

2.1.4 content md5

如果请求包含body内容 (可以为空),则要基于body内容计算出md5值,只有在请求存在body且为非 form形式时才计算md5值。

form即content-type为如下形式:

  • multipart/form-data
  • application/x-www-form-urlencoded

Go语言示例:

func Md5(str string) string {
   hash := md5.New()
   hash.Write([]byte(str))
   sum := hash.Sum(nil)
   sign := hex.EncodeToString(sum)
   return sign
}

2.1.5 query parameters

包含请求query参数 和 form表单提交的所有参数。

  1. 将参数的key按照字典序排序后进行下面方式的拼接,格式 K1+"="+V1+"&"+K2+"="+V2+"&" + ... + Kn+"="+Vn
  2. query和form参数的值value为空时,只保留key参与签名,"="不参与签名。
  3. query和form都不存在时,整体不参与签名。
  4. query和form存在数组参数时,取第一个value参与签名计算。
  5. query和form包含相同key时,取query的内容参与签名计算。

传数组方式举例:

2.2 计算签名

客户端从要发送的HTTP请求中提取出关键数据拼接成待签名字符串后,要使用相应的加密算法,并使用 APP Secret参与其中。最后再对结果进行编码处理,形成最终的签名,目前API支持两种加密算法:

  • HmacSHA256
  • HmacSHA1

将待签名字符串(StringToSign)使用 UTF-8 编码后得到Byte数组,然后使用加密算法对 Byte数组进行签名,签名使用 APP Secret的值作为key,最后使用十六进制进行转码,形成最终签名。

Go语言示例:

func HmacSha256(key, str string) string {
	hash := hmac.New(sha256.New, []byte(key))
	hash.Write([]byte(str))
	sum := hash.Sum(nil)

	sign := hex.EncodeToString(sum)
	return sign
}

2.3 传输签名

客户端需要将以下内容放入到http请求的header中,请求给到服务端网关,API网关会做签名比对。

tw-signature-headers: tw-appkey,tw-signature-method,tw-nonce,tw-timastamp

  • tw-appkey: 分配给客户端的账户名。必填
  • tw-signature:签名。必填
  • tw-signature-method:签名算法,取值HmacSHA256或者HmacSHA1,默认值为HmacSHA256。选填
  • tw-signature-headers: 所有参与签名的header头key的集合,使用逗号分隔。选填
  • tw-nonce:随机字符串,用于防止防重放攻击。选填
  • tw-timestamp:时间戳,精确到毫秒,用于防止重放攻击。选填

三、示例

3.1 GET 示例

curl --location --request GET --X GET 'http://localhost/hello/demo1?name=tom&detail=yes' \
--header 'tw-appkey: abcde' \
--header 'tw-signature-headers: tw-appkey,tw-signature-method'

步骤:

  • 请求方法, GET
  • 请求url的path, /hello/demo1
  • 参照tw-signature-headers中的内容,获取2个header内容拼接字符串,每个header部分用"\n"回车符连接。签名方法没有传,所以默认用HmacSHA256。
tw-appkey:aaabbb
tw-signature-method:HmacSHA256
  • 由于是GET请求,不处理body部分,content md5没有。
  • 有query参数部分,name和detail按照字典序排序后拼接得到字符串,detail=yes&name=tom
  • 把上面每个部分的内容用回车符拼接,得到待签名字符串
GET
/hello/demo1
tw-appkey:aaabbb
tw-signature-method:HmacSHA256
detail=yes&name=tom
  • 对上面字符串,采用HmacSHA256签名,使用APP Secret值作为密钥,然后进行十六进制转码。
  • 把签名放到 header头 tw-signature中一起发送。

3.2 POST表单示例

curl --location --request POST --X POST 'http://localhost/hello/demo2?name=tom&detail=yes' \
--header 'tw-nonce: asfaw345gee54feg' \
--header 'tw-timestamp: 1723081712335' \
--header 'tw-appkey: aaabbb' \
--header 'tw-signature-headers: tw-appkey,tw-signature-method,tw-nonce,tw-timestamp' \
--header 'tw-signature-method: HmacSHA1' \
--form 'username=john' \
--form 'password=admin'

步骤:

  • 请求方法,POST
  • 请求url的path,  /hello/demo2
  • 参照tw-signature-headers中的内容,获取4个header内容拼接字符串,每个header部分用"\n"回车符连接。
tw-appkey:aaabbb
tw-nonce:asfaw345gee54feg
tw-signature-method:HmacSHA1
tw-timestamp:1723081712335
  • 虽然是POST请求,但是属于form表单,不处理body部分,content md5没有。
  • 有query部分,也有form表单参数部分,所有字段按照字典序排序后拼接得到字符串,detail=yes&name=tom&password=admin&username=john
  • 把上面每个部分的内容用回车符拼接,得到待签名字符串
POST
/hello/demo2
tw-appkey:aaabbb
tw-nonce:asfaw345gee54feg
tw-signature-method:HmacSHA1
tw-timestamp:1723081712335
detail=yes&name=tom&password=admin&username=john
  • 签名方法传了HmacSHA1,对上面字符串,采用HmacSHA1签名,使用APP Secret值作为密钥,然后进行十六进制转码。
  • 把签名放到 header头 tw-signature中一起发送。

3.3 POST json示例

curl --location --request POST --X POST 'http://localhost/hello/demo3' \
--header 'tw-nonce: asfaw345gee54feg' \
--header 'tw-timestamp: 1723081712335' \
--header 'tw-appkey: aaabbb' \
--header 'tw-signature-headers: tw-appkey,tw-signature-method,tw-nonce,tw-timestamp' \
--header 'tw-signature-method: HmacSHA256' \
--header 'Content-Type: application/json' \
--data '{
	"name": "john"
}'

步骤:

  • 请求方法,POST
  • 请求url的path,  /hello/demo3
  • 参照tw-signature-headers中的内容,获取4个header内容拼接字符串,每个header部分用"\n"回车符连接。
POST
/hello/demo3
tw-appkey:aaabbb
tw-nonce:asfaw345gee54feg
tw-signature-method:HmacSHA256
tw-timestamp:1723081712335
  • POST请求,且非form提交方式,查看到有body内容,对json内容进行md5,得到be6c45653b7a872980b27d9dd8d2e0ac
  • 没有query参数,因此内容为空
  • 把上面每个部分的内容用回车符拼接,得到待签名字符串
POST
/hello/demo3
tw-appkey:aaabbb
tw-nonce:asfaw345gee54feg
tw-signature-method:HmacSHA256
tw-timestamp:1723081712335
be6c45653b7a872980b27d9dd8d2e0ac
  • 签名方法传了HmacSHA256,对上面字符串,采用HmacSHA256签名,使用APP Secret值作为密钥,然后进行十六进制转码。
  • 把签名放到 header头 tw-signature中一起发送。

  • 18
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值