API 接口签名

为什么要做API 接口签名?

我先描述一个场景:微信中一个好久没有聊天的朋友突然向你借钱,你会这么想 ?

我想大部分人马上的反应就是:他是不是被盗号了?他是本人吗?

其实这个就和公司中前端调用对应的API 或者是提供接口给其他公司调用一样,在进行数据传输的过程中,其实数据都是可以被抓包工具进行截取,甚至被篡改的。因而数据传输就存在着极大的危险,为了保证接口的安全性,需要设计一些方式来对接口进行保护,市面上常见的保护措施有 IP 白名单API接口签名
IP 白名单实现起来其实很简单,使用AOP切面去,断接口调用者 IP 是否在设定的白名单 IP 之中即可。但是 IP 白名单这种方式有个很大的弊端就是维护白名单 IP 列表成了体力活,调用方增加服务器或者减少服务器就要更新白名单,维护起来异常麻烦。
所以一般来说都会去考虑API接口签名。

API接口签名核心需要解决三个问题:

  1. 请求是否合法:是否是我规定的那个人
  2. 请求是否被篡改:是否被第三方劫持并篡改参数
  3. 防止重复请求(防重放):是否重复请求

签名算法逻辑

一般来说,接口签名方式主要是这样的,所有的接口都需要传递这几个公共参数appKeysigntimestampnoncesign 的计算规则为:

  1. 拼接接口的所有参数,参数名按照 ASCII 码从小到大排序,拼接的格式如 k1=v1&k2=v2&k3=v3 得到params
  2. 在params的最后再拼接appKey密钥
  3. 通过某种加密算法或通过hash算法得到 sign 值(一般为Base64(HMAC_SHA1(params, appSecret))
  4. sign加到params 中,将params放入请求头中发送请求目标接口

以上就是生成签名的过程。

这样后端就可以从请求头中拿到对应的签名,后端再通过前端相同的算法去生成sign,如果生成的sign和前端请求头中的sgin相同,则表示该请求并没有被篡改

防重放攻击

但是以上措施依然不是最严谨的,虽然仿冒者无法轻易模仿签名规则再生成一模一样的签名,可实际上,如果仿冒者监听并截取到了请求片段,然后把签名单独截取出来模仿正式请求方欺骗服务器进行重复请求,这也会造成安全问题,这攻击方式就叫重放攻击(replay 攻击)。
我们一般使用 timestamp + nonce 两个参数来控制请求有效性,防止重放攻击。

timestamp

timestamp 由请求端生成,代表着请求发送的时间,将其放到params中一同放在请求头中发出,同时将timestamp也作为一个参数加入sign的计算之中

后端收到请求后,将timestamp解析出来,判断当前时间和请求发送的时间是否相差10s(这个时间就由前后端自己商量一个恰当的时间),如果不超出这个时间则认为时间正常,如果超出则直接抛出对应的异常。

nonce

nonce 是由请求方生成的随机数(在规定的时间内保证有充足的随机数产生,即在10s 内产生的随机数重复的概率为0)也作为参数之一加入 sign 签名。

后端在接受到请求后,将timestamp解析出来,去判定 nonce 是否被请求过(一般请求过的noces会放到redis中),如果redis中存在对应的nonce就证明这次请求是重放攻击,直接抛出对应的异常

我对于API 接口签名的大概就是这些,如果有什么不对的地方欢迎指正

你可能感兴趣的:(java,java,前端,后端)