暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

开放API接口签名验证

老胡的技术笔记 2021-05-31
1469
01
前言

前后端分离的开发方式,我们以接口为标准来进行推动,定义好接口,各自开发自己的功能,最后进行联调整合。无论是开发原生的APP还是webapp还是PC端的软件,只要是前后端分离的模式,就避免不了调用后端提供的接口来进行业务交互。
网页或者app,只要抓下包就可以清楚的知道这个请求获取到的数据,也可以伪造请求去获取或攻击服务器。先考虑一下接口数据被伪造,以及接口被重复调用的问题,要解决这个问题我们就要用到接口签名的方案
02
正文

签名流程:

参数说明

关键参数

参数名

参数作用

说明

source_system

系统来源

用于区分不同客户端来源。并根据不同的客户端来源获取source_secret用于生产signature签名

前后端按照约定线下分配

request_id

请求流水号

用于判断是否重复请求

随机生产,唯一性

request_time

请求时间

用于请求连接过期,让链接有失效时间

单位毫秒

access_token

令牌

权限验证

采用Spring Security OAuth 2.0生成

signature

签名

用于比较参数是否篡改

不可逆加密方式

签名规则:

1、线下分配source_systemsource_secret,针对不同的调用方分配不同的source_system和source_secret
2、加入request_time 作为请求的时间戳,5分钟内数据有效
3、加入临时流水号request_id(防止重复提交),每次请求生成的随机字符串。同时流水号也用于日志落地,便于后期日志核查。流水号存在有效期、唯一性,以避免重复请求
4、加入签名字段signature,所有数据的签名信息。
以上字段放在请求头中

签名的生成:

签名signature字段生成规则
所有动态参数 = 请求头部分 + 请求URL地址 + 请求Request参数 + 请求Body
上面的动态参数以key-value的格式存储,并以key值正序排序,进行拼接
最后拼接的字符串 在拼接source_secret。
signature =DigestUtils.md5DigestAsHex(sortParamsMap +source_secret)
拼接成一个字符串,然后做md5不可逆加密

签名算法实现:

自定义filter过滤器,对每个请求进行拦截处理;整体流程如下

1)验证必须的头部参数

2)获取头部参数,Request参数,Url请求路径,请求体Body,把这些值放入SortMap中进行排序

3)对SortMap里面的值进行拼接

4)对拼接的值进行加密,生成signature

5)把生成的signature和前端传入的signature进行比较,如果不相同就返回错误

代码实现:

以上是filter过滤器,其中有个RequestWrapper继承HttpServletRequestWrapper来获取请求流(请求流只能获取一次,参数后续需要进行校验,因此暂存了请求流中的请求信息)

验证头部参数:

上图其实就是验证是否传入值;不过其实有个很重要的一点,就是对此请求进行时间验证,如果大于10分钟表示此链接已经超时,防止别人来到这个链接去请求。这个就是防止盗链。

如何获取各个参数:


上面我们获取了各个参数,并把参数信息放到了一个以key值正序排序的SortMap

生成signature签名,并验证和前端传入的signature进行比较


将暂存的请求流中的参数信息放入到SortMap中,根据自己的规则对SortMap里面的值进行拼接,即拼接成一个字符串并转换成小写,然后做md5不可逆加密。

重放攻击处理方案:

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

request_time +request_id方案

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

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

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

重放攻击处理方案

  • 防止盗链,我们可以让链接有失效时间

  • 利用流水号request_id参数,防止重复提交

在签名验证成功后,判断是否重复提交;
原理就是结合redis,判断是否已经提交过

END


文章转载自老胡的技术笔记,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论