先后端分离的开发方式,咱们以接口为标准来进行推进,定义好接口,各自开发本身的功能,最后进行联调整合。不管是开发原生的APP仍是webapp仍是PC端的软件,只要是先后端分离的模式,就避免不了调用后端提供的接口来进行业务交互。前端
网页或者app,只要抓下包就能够清楚的知道这个请求获取到的数据,也能够伪造请求去获取或攻击服务器;也对爬虫工程师来讲是一种福音,要抓你的数据简直垂手可得。那咱们怎么去解决这些问题呢?java
咱们先考虑一下接口数据被伪造,以及接口被重复调用的问题,要解决这个问题咱们就要用到接口签名的方案,web
一、线下分配appid和appsecret,针对不一样的调用方分配不一样的appid和appsecretredis
二、加入timestamp(时间戳),5分钟内数据有效算法
三、加入临时流水号 nonce****(防止重复提交),至少为10位。针对查询接口,流水号只用于日志落地,便于后期日志核查。针对办理类接口需校验流水号在有效期内的惟一性,以免重复请求。后端
四、加入签名字段signature,全部数据的签名信息。api
以上字段放在请求头中。安全
签名signature字段生成规则服务器
全部动态参数 = 请求头部分 + 请求URL地址 + 请求Request参数 + 请求Bodyapp
上面的动态参数以key-value的格式存储,并以key值正序排序,进行拼接
最后拼接的字符串 在拼接appSecret
signature = DigestUtils.md5DigestAsHex(sortParamsMap + appSecret)
即拼接成一个字符串,而后作md5不可逆加密
请求头=“appId=xxxx&nonce=xxxx×tamp=xxxx&sign=xxx”
请求头中的4个参数是必需要传的,不然直接报异常
这个就是请求接口的地址包含协议,如
https://mso.xxxx.com.cn/api/user
即请求为Get方式的时候,获取的传入的参数
即请求为Post时,请求体Body
从request inputstream中获取保存为String形式
基本原理其实也比较简单,就是自定义filter,对每一个请求进行处理;总体流程以下:
验证必须的头部参数
获取头部参数,request参数,Url请求路径,请求体Body,把这些值放入SortMap中进行排序
对SortMap里面的值进行拼接
对拼接的值进行加密,生成sign
把生成的sign和前端传入的sign进行比较,若是不相同就返回错误
咱们来看一下代码
@Component public class SignAuthFilter extends OncePerRequestFilter{ static final String FAVICON = "/favicon.ico"; static final String PREFIX = "attack:signature:"; }
以上是filter类,其中有个appSecret须要本身业务去获取,它的做用主要是区分不一样客户端app。而且利用获取到的appSecret参与到sign签名,保证了客户端的请求签名是由咱们后台控制的,咱们能够为不一样的客户端颁发不一样的appSecret。
咱们再来看看验证头部参数
上图其实就是验证是否传入值;不过其实有个很重要的一点,就是对此请求进行时间验证,若是大于10分钟表示此连接已经超时,防止别人来到这个连接去请求。这个就是防止盗链。
咱们在来看看,如何获取各个参数
上面咱们获取了各个参数,相对比较简单;咱们在来看看生成sign,和验证sign
上面的流程中,会有个额外的安全处理,
· 防止盗链,咱们可让连接有失效时间
· 利用nonce参数,防止重复提交
在签名验证成功后,判断是否重复提交;
原理就是结合redis,判断是否已经提交过
今天咱们用签名的方式,对咱们对外提供的接口起到了保护做用;但这种保护仅仅作到了防止别人篡改请求,或者模拟请求。
可是仍是缺乏对数据自身的安全保护,即请求的参数和返回的数据都是有可能被别人拦截获取的,而这些数据又是明文的,因此只要被拦截,就能得到相应的业务数据。