腾讯云阿里云API接口签名鉴权方法

不管是腾讯云还是阿里云的API,防止篡改、重放都是基本要求,他们的接口鉴权算法也是一样的,这个鉴权的方法也是通用的。

假如有一个接口测算两个名字的缘分,比如shabia和tiancaib的缘分值为0.001,
大致就是GET qcloud.com?action=calcyf&name1=shabia&name2=tiancaib

问题来了,上面的这些参数是如何做到鉴权和防止重放的?

1.身份标识ID和KEY

在腾讯云或阿里云的后台,API接口的调用都要求先创建调用者身份标识ID和KEY。
腾讯云管它们叫SecretId和SecretKey,阿里云管它们叫AccessKeyID和AccessKeySecret,不同的马甲而已,一个东西。
身份ID和KEY是用户在云后台获取到的,并且要求用户做好保密,这意味着用户知道ID和KEY,腾讯云或者阿里云也可以根据ID查询到KEY。

2.对请求字符串进行签名

鉴权是通过使用客户端和服务端都知道的KEY对请求字符串按照相同的算法进行摘要提取,两者一致的话,鉴权成功,否则,鉴权失败。

在请求的参数中,action=calcyf是一个参数,指定调用的功能类型;name1=shabia 和name2=tiancaib都是功能实现需要的参数,不做解释。
带上id=ID,这样服务端才知道你是谁,才能找出来ID和KEY。

在action=calcyf&id=ID&name1=shabia&name2=tiancaib这个请求中,接口一般要求对请求参数进行排序后组织,
对参数进行排序,是对指定参数集构造唯一字符串的一个简单方法,腾讯云要求对参数按照参数名称的ASCII升序排列参数,因此action>id>name1>name2。

排好序后,得到的请求参数字符串就是action=calcyf&id=ID&name1=shabia&name2=tiancaib ,记为strRequest。

那么签名signature=base64(sha1(strRequest,KEY)),服务端只需要按照这个方法也算一下signature,相同则表明调用身份合法,参数在传递过程中也没有被篡改。

3.如何防止重放

在action=calcyf&id=ID&name1=shabia&name2=tiancaib&signature=xxxx这个串里,
没有时间戳信息,服务器不知道这个请求是什么时间生成的,这就意味着如果报文被捕获,就可以无限次重放,至少鉴权可以通过。
解决的办法是在请求参数中加上一个时间戳参数,这样请求串变成了:
action=calcyf&id=ID&name1=shabia&name2=tiancaib&timestamp=123456789&signature=xxxx
服务器检查时间戳参数距离现在多久了,如果超过30秒,认为请求无效,这个30秒的时间,不同云厂家可能不一样。

重放的问题还没有解决,至少在30秒内还可以重放攻击。
解决的方法也比较简单直接,就是再新增一个随机数作为参数,客户端只需要保证这个随机数在30秒内不会重复即可。这个随机数大家都叫它nonce。
加入nonce后的请求串就变成了
action=calcyf&id=ID&name1=shabia&name2=tiancaib&nonce=123456&timestamp=123456789&signature=xxxx
比如客户端使用rand生成随机整数作为nonce,那么基本可以任务30秒内不会出现重复的nonce。
服务器只需要记录下该接口该用户在30秒内用过的nonce,如果发现相同nonce在30秒时间窗口内重复出现,就判定为重放攻击。

如何实现这个30秒内的统计呢,比较简单的可以使用redis的超时机制。针对每一个请求,构造{action}{ID}{nonce}作为key的元素,值随意,以30秒有效期写入redis。
比如上面的,构造的key就是calcyf_ID_123456,剩下的大概知道的。

至于redis的性能,就不需要替大厂担心了,这种基础产品,几千万QPS都是小事。