API接口签名生成算法和签名验证算法

为了接口安全,需要做API接口校验。

接口安全问题

  • 请求身份是否合法?
  • 请求参数是否被篡改?
  • 请求是否唯一?

1.请求身份

为开发者分配AppKey(开发者标识,确保唯一)和AppSecret(用于接口加密,确保不易被穷举,生成算法不易被猜测)。

2.防止篡改

参数签名

按照请求参数名的字母升序排列非空请求参数(包含AppKey),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA;
在stringA最后拼接上AppSecret得到字符串stringSignTemp;
对stringSignTemp进行MD5运算,并将得到的字符串所有字符转换为大写,得到sign值。

请求携带参数AppKey和Sign,只有拥有合法的身份AppKey和正确的签名Sign才能放行。这样就解决了身份验证和参数篡改问题,即使请求参数被劫持,由于获取不到AppSecret(仅作本地加密使用,不参与网络传输),无法伪造合法的请求。

3.重放攻击

虽然解决了请求参数被篡改的隐患,但是还存在着重复使用请求参数伪造二次请求的隐患。

timestamp+nonce方案

nonce指唯一的随机字符串,用来标识每个被签名的请求。通过为每个请求提供一个唯一的标识符,服务器能够防止请求被多次使用(记录所有用过的nonce以阻止它们被二次使用)。

然而,对服务器来说永久存储所有接收到的nonce的代价是非常大的。可以使用timestamp来优化nonce的存储。

假设允许客户端和服务端最多能存在15分钟的时间差,同时追踪记录在服务端的nonce集合。当有新的请求进入时,首先检查携带的timestamp是否在15分钟内,如超出时间范围,则拒绝,然后查询携带的nonce,如存在已有集合,则拒绝。否则,记录该nonce,并删除集合内时间戳大于15分钟的nonce(可以使用redis的expire,新增nonce的同时设置它的超时失效时间为15分钟)。

4.实现算法

API接口签名生成算法Demo

主要步骤如下:

假设请求的参数为:key1=value1,key2=value2,key3=value3

(1)将所有业务请求参数按字母先后顺序排序。

(2)参数名称和参数值链接成一个字符串A。

(3)在字符串A的首尾加上apiSecret接口密匙组成一个新字符串B。

(4)对字符串进行MD5散列运算得到API签名sign,然后再进行Base64编码。

假设请求的参数为:key1=value1,key2=value2,key3=value3,排序后为key1=value1,key2=value2,key3=value3(示例),参数名和参数值链接后为key1value1key2value2key3value3,首尾加上appsecret后md5:

C = md5(appsecret1value1key2value2...appsecret);

Base64.encode(C );

以上签名方法安全有效地解决了参数被篡改和身份验证的问题,如果参数被篡改,因为别人无法知道AppSecret,也就无法重新生成新的sign,从而保证接口调用是可靠的。

签名验证算法(接口提供方验证接口请求是否可信,主要算法跟生成API签名的算法是一样的)

  检查API签名是否合法
(1)客户端请求里面会携带签名(客户端利用apiSecret和给定的算法产生签名)
(2)服务器端会使用存在服务器端的apiSecret和相同的算法产生一个签名。
(3)服务器端对这两个签名进行校验,得出签名的有效性。如果有效,则正常走业务流程,否则拒绝请求。

主要步骤如下:

1、得到请求方携带的API签名。

2、将所有业务请求参数按字母先后顺序排序。

3、参数名称和参数值链接成一个字符串A。

4、在字符串A的首尾加上AppSecret接口密匙组成一个新字符串B。

5、对新字符串B进行MD5散列运算生成服务器端的API签名,将客户端的API签名进行Base64解码,然后开始验证签名。

6、如果服务器端生成的API签名与客户端请求的API签名是一致的,则请求是可信的,否则就是不可信的。

开放平台以及公网的的api设计,都可以参考类似算法。

Sign签名安全性分析:

通过上面的案例,我们可以看出,安全的关键在于参与签名的secret,整个过程中secret是不参与通信的,所以只要保证secret不泄露,请求就不会被伪造。

总结

上述的Sign签名的方式能够在一定程度上防止信息被篡改和伪造,保障通信的安全,这里使用的是MD5进行加密,当然实际使用中大家可以根据实际需求进行自定义签名算法,比如:RSA,SHA等。

(完)

发表评论

邮箱地址不会被公开。 必填项已用*标注