提供给第三方的业务接口应该如何设计呢?需要从哪些方面考虑?以及如何实现这些方面?
1、标准化
RESTful
2、安全性
1)请求token
token作为调用系统的凭证。token可以设置一次有效(安全性最高),不过推荐设置时效性,减少获取获取token接口的请求频率。 token建议放在请求头上,这样可以跟业务参数完全区分开。
获取token一般会涉及的几个参数:appId、appKey、timestamp、nonce(requestId)、sign
appId和appKey通过开发平台申请和下发,appId即应用Id,是请求方的全局唯一的标识,一个appId对应一个客户,appKey需要高度保密,用于接口加密时拼装appKey作为加密串,不作为网络传输。
timestamp是时间戳,目的是为了减轻DOS攻击。防止请求被拦截后一直尝试请求接口。服务器设置时间戳阀值(5s),如果请求时间戳和服务器时间超过阀值,则响应失败。
nonce(requestId)是随机值,目的是为了增加sign的多变性,也可以保护接口的幂等性,相邻的两次请求nonce不允许重复,如果重复则认为是重复提交,响应失败。(将每次请求的nonce参数存储到缓存中,每次请求去缓存中查询是否存在,如果存在则认为是非法请求)
sign是参数签名,将appId,nonce,timestamp,还有其余非空请求参数,按照字母升序排列,然后使用URL键值对的格式(key1=value1&key2=value2)拼接起来,最后再拼接上appKey,组成待签名串;然后进行md5加密生成签名(或其他不可逆加密方式(如RSA2),有的情况要求先对待签名串进行UrlEncode,然后再加密生成签名)
请求携带appId和sign,只有拥有合法的身份appId和正确的签名sign才放行。
2)加密签名
对敏感入参进行AES加密,防止数据泄漏
对所有请求参数拼装后进行RSA签名,防止参数遭篡改。请求进来之后先验证签名,签名不匹配直接返回失败
(对于客户端与服务端的交互,AES密钥应使用动态密钥,每次由客户端生成AES密钥,并使用公钥进行加密传给服务端(RSA私钥保存在服务端))
3)客户端IP白名单
限流是为了更好的维护系统稳定性。防止接口遭恶意大量频繁调用(盗刷)。使用Redis进行接口调用次数统计,ip+接口地址作为key,访问次数作为value,每次请求value+1,设置过期时长来限制接口的调用频率。
4)限流
可使用阿里的Sentinel限流工具:https://github.com/alibaba/Sentinel
3、幂等性
幂等性是指任意多次请求的执行结果和一次请求的执行结果所产生的影响相同。
如查询删除是幂等的,新增修改是非幂等的。
解决方案:
服务方提供一个生成全局唯一随机数token的接口,客户端在调用业务接口前先向服务方发送请求获取token,在客户端获取token的时候,将token存入redis中。
① 服务方提供获取token的接口,token可以是uuid
② 客户端在调用业务接口前先调用接口获取token
③ 服务方在客户端获取token时,生成token,并将token 作为 key,客户端用户信息作为value,保存在redis中,然后返回token
④ 客户端请求业务接口时,将获取的token放在header(最好放在header中)或者作为请求参数请求接口
⑤ 服务端收到请求后,从headers中拿到token,然后根据token到redis中查找该key是否存在
⑥ 如果存在,业务处理成功后,从redis中删除此token。如果不存在,说明重复调用,返回请勿重复操作即可
注意:从redis中查询token和删除token,要保证原子性,应使用redis分布式锁
https://www.cnblogs.com/yangyongjie/p/13724165.html
4、规范标准
1)加密、签名方式规范
敏感字段采用AES加密,模式为CBC,具体算法为 AES/CBC/PKCS5Padding。
签名的作用:对数据进行签名后,可以保证数据完整性,机密性和发送方角色的不可抵赖性,可以有效防止请求信息信息被篡改
签名方式采用RSA2(签名算法为SHA256WithRSA,要求RSA密钥的长度至少为2048位),步骤如下:
1)筛选并排序
获取所有请求参数,不包括字节类型参数(如文件,字节流),剔除sign参数和值为空的参数,并且参数名和参数值前后不要带有空格,并按照参数名的第一个字符的键值ASCII码递增排序(字母升序排序),如果遇到相同字符则按照第二个字符的键值 ASCII 码递增排序,以此类推;
2)拼接
将排序后的参数与其对应值,组合成“参数=参数值”的格式,并且把这些参数用 & 字符连接起来,此时生成的字符串为待签名字符串
3)签名
最后对待签名串签名,并进行BASE64编码。然后将生成的签名赋值给sign参数,拼接到请求参数中
2)请求方式为POST
除了sign参数外,其他参数全部以JSON格式放在body中。
请求方需要对sign进行UrlEncode,且Content-Type:application/json; charset=utf-8
3)接口返回规范
返回类型为JSON格式,包含状态码code、描述msg、响应数据data,返回码和描述提前定义好。必要的话,对响应的参数进行签名赋值给sign参数一并返回。
4)统一参数校验和验签,打印请求日志
使用AOP全局记录请求日志(请求接口URL,请求参数),响应日志。设置请求线程号,用于快速定位异常请求位置,排查问题原因
使用另一个AOP统一进行参数非空校验、签名校验、token校验,不通过直接返回失败,不进入业务代码。
END.