为了接口安全,需要做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等。
(完)