API接口设计:防参数篡改+防二次请求
API接口由于需要供第三方服务调用,所以必须暴露到外网,并提供了具体请求地址和请求参数
为了防止被第别有用心之人获取到真实请求参数后再次发起请求获取信息,需要采取很多安全机制
1.首先: 需要采用https方式对第三方提供接口,数据的加密传输会更安全,即便是被破解,也需要耗费更多时间
2.其次:需要有安全的后台验证机制【本文重点】,达到防参数篡改+防二次请求
主要防御措施可以归纳为两点:
- 对请求的合法性进行校验
- 对请求的数据进行校验
防止重放攻击必须要保证请求仅一次有效
需要通过在请求体中携带当前请求的唯一标识,并且进行签名防止被篡改。
所以防止重放攻击需要建立在防止签名被串改的基础之上。
请求参数防篡改
采用https协议可以将传输的明文进行加密,但是黑客仍然可以截获传输的数据包,进一步伪造请求进行重放攻击。如果黑客使用特殊手段让请求方设备使用了伪造的证书进行通信,那么https加密的内容也将会被解密。
在API接口中我们除了使用https协议进行通信外,还需要有自己的一套加解密机制,对请求参数进行保护,防止被篡改。
过程如下:
- 客户端使用约定好的秘钥对传输参数进行加密,得到签名值signature,并且将签名值也放入请求参数中,发送请求给服务端
- 服务端接收客户端的请求,然后使用约定好的秘钥对请求的参数(除了signature以外)再次进行签名,得到签名值autograph。
- 服务端对比signature和autograph的值,如果对比一致,认定为合法请求。如果对比不一致,说明参数被篡改,认定为非法请求。
因为黑客不知道签名的秘钥,所以即使截取到请求数据,对请求参数进行篡改,但是却无法对参数进行签名,无法得到修改后参数的签名值signature。
签名的秘钥我们可以使用很多方案,可以采用对称加密或者非对称加密。
防止重放攻击
基于timestamp的方案
每次HTTP请求,都需要加上timestamp参数,然后把timestamp和其他参数一起进行数字签名。因为一次正常的HTTP请求,从发出到达服务器一般都不会超过60s,所以服务器收到HTTP请求之后,首先判断时间戳参数与当前时间相比较,是否超过了60s,如果超过了则认为是非法的请求。
一般情况下,黑客从抓包重放请求耗时远远超过了60s,所以此时请求中的timestamp参数已经失效了。
如果黑客修改timestamp参数为当前的时间戳,则signature参数对应的数字签名就会失效,因为黑客不知道签名秘钥,没有办法生成新的数字签名。
但这种方式的漏洞也是显而易见的,如果在60s之后进行重放攻击,那就没办法了,所以这种方式不能保证请求仅一次有效。
基于nonce的方案
nonce的意思是仅一次有效的随机字符串,要求每次请求时,该参数要保证不同,所以该参数一般与时间戳有关,我们这里为了方便起见,直接使用时间戳的16进制,实际使用时可以加上客户端的ip地址,mac地址等信息做个哈希之后,作为nonce参数。
我们将每次请求的nonce参数存储到一个“集合”中,可以json格式存储到数据库或缓存中。
每次处理HTTP请求时,首先判断该请求的nonce参数是否在该“集合”中,如果存在则认为是非法请求。
nonce参数在首次请求时,已经被存储到了服务器上的“集合”中,再次发送请求会被识别并拒绝。
nonce参数作为数字签名的一部分,是无法篡改的,因为黑客不清楚token,所以不能生成新的sign。
这种方式也有很大的问题,那就是存储nonce参数的“集合”会越来越大,验证nonce是否存在“集合”中的耗时会越来越长。我们不能让nonce“集合”无限大,所以需要定期清理该“集合”,但是一旦该“集合”被清理,我们就无法验证被清理了的nonce参数了。也就是说,假设该“集合”平均1天清理一次的话,我们抓取到的该url,虽然当时无法进行重放攻击,但是我们还是可以每隔一天进行一次重放攻击的。而且存储24小时内,所有请求的“nonce”参数,也是一笔不小的开销。
基于timestamp和nonce的方案
nonce的一次性可以解决timestamp参数60s的问题,timestamp可以解决nonce参数“集合”越来越大的问题。
防止重放攻击一般和防止请求参数被串改一起做,请求的Headers数据如下图所示。
我们在timestamp方案的基础上,加上nonce参数,因为timstamp参数对于超过60s的请求,都认为非法请求,所以我们只需要存储60s的nonce参数的“集合”即可。
最终实现代码(网关层验证):
public class APIAuth extends ZuulFilter {
@Override
public String filterType() {
return "pre";
} @Override
public int filterOrder() {
return 0;
} @Override
public boolean shouldFilter() {
return true;
} @Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest(); String token = request.getHeader("token");
String timestamp = request.getHeader("timestamp");
String nonce = request.getHeader("nonce");
String sign = request.getHeader("sign"); //时间限制配置
int timeLimit = 60; ctx.setSendZuulResponse(false); //请求头参数非空验证
if (StringUtils.isEmpty(token) || StringUtils.isEmpty(timestamp) || StringUtils.isEmpty(nonce) || StringUtils.isEmpty(sign)) {
ctx.setResponseBody(JSON.toJSONString(new Result("-1", "请求头参数不正确")));
return null;
} //请求时间和现在时间对比验证,发起请求时间和服务器时间不能超过timeLimit秒
if (StringUtils.timeDiffSeconds(new Date(), timestamp) > timeLimit) {
ctx.setResponseBody(JSON.toJSONString(new Result("-1", "请求发起时间超过服务器限制")));
return null;
} //验证用户信息
UserInfo userInfo = UserInfoUtil.getInfoByToken(token);
if (userInfo == null) {
ctx.setResponseBody(JSON.toJSONString(new Result("-1", "错误的token信息")));
return null;
} //验证相同noce的请求是否已经存在,存在表示为重复请求
if (NoceUtil.exsit(userInfo, nonce)) {
ctx.setResponseBody(JSON.toJSONString(new Result("-1", "重复的请求")));
return null;
} else {
//如果noce没有在缓存中,则需要加入,并设置过期时间为timeLimit秒
NoceUtil.addNoce(userInfo, nonce, timeLimit);
} //服务器生成签名与header中签名对比
String serverSign = SignUtil.getSign(userinfo, token, timestamp, nonce, request);
if (!serverSign.equals(sign)) {
ctx.setResponseBody(JSON.toJSONString(new Result("-1", "错误的签名信息")));
return null;
} ctx.setSendZuulResponse(true);
return null;
}
}
API接口设计:防参数篡改+防二次请求的更多相关文章
- Java生鲜电商平台-API接口设计之token、timestamp、sign 具体架构与实现(APP/小程序,传输安全)
Java生鲜电商平台-API接口设计之token.timestamp.sign 具体设计与实现 说明:在实际的业务中,难免会跟第三方系统进行数据的交互与传递,那么如何保证数据在传输过程中的安全呢(防窃 ...
- API接口设计之token、timestamp、sign 具体架构与实现(APP/小程序,传输安全)
Java生鲜电商平台-API接口设计之token.timestamp.sign 具体设计与实现 说明:在实际的业务中,难免会跟第三方系统进行数据的交互与传递,那么如何保证数据在传输过程中的安全呢(防窃 ...
- atitit.基于http json api 接口设计 最佳实践 总结o7
atitit.基于http json api 接口设计 最佳实践 总结o7 1. 需求:::服务器and android 端接口通讯 2 2. 接口开发的要点 2 2.1. 普通参数 meth,p ...
- Web API接口设计经验总结
在Web API接口的开发过程中,我们可能会碰到各种各样的问题,我在前面两篇随笔<Web API应用架构在Winform混合框架中的应用(1)>.<Web API应用架构在Winfo ...
- Web API接口设计(学习)
1.在接口定义中确定MVC的GET或者POST方式 由于我们整个Web API平台是基于MVC的基础上进行的API开发,因此整个Web API的接口,在定义的时候,一般需要显示来声明接口是[HttpG ...
- API接口设计
1.场景描述 比如说我们要做一款APP,需要通过api接口给app提供数据.假设我们是做商城,比如我们卖书的.我们可以想象下这个APP大概有哪些内容: 1)首页:banner区域(可以是一些热门书籍的 ...
- Spring Boot web API接口设计之token、timestamp、sign
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/vbirdbest/article/details/80789817一:token 简介Token:访 ...
- Java生鲜电商平台-API接口设计之token、timestamp、sign 具体设计与实现
转载:https://www.cnblogs.com/jurendage/p/12653865.html 说明:在实际的业务中,难免会跟第三方系统进行数据的交互与传递,那么如何保证数据在传输过程中的安 ...
- 优秀的API接口设计原则及方法(转)
一旦API发生变化,就可能对相关的调用者带来巨大的代价,用户需要排查所有调用的代码,需要调整所有与之相关的部分,这些工作对他们来说都是额外的.如果辛辛苦苦完成这些以后,还发现了相关的bug,那对用户的 ...
随机推荐
- Python面向对象编程(上)
Python不仅支持面向过程编程,同时也支持面向对象编程.面向工程就是分析解决问题所需的步骤,然后用函数把这些步骤逐一实现,使用的时候再一个个调用函数就可以.面向对象则是把解决的问题按照一定规则划分为 ...
- NYOJ252-01串-(数位dp)
252-01串 内存限制:64MB 时间限制:1000ms 特判: No通过数:33 提交数:49 难度:2 题目描述: ACM的zyc在研究01串,他知道某一01串的长度,但他想知道不含有“11”子 ...
- OpenCV常用数据类型
Point 二维点坐标(x,y) typedef Point3_<int> Point3i; typedef Point3_<float> Point3f; typedef P ...
- ABAP 省市县级联搜索帮助
在展示ABAP代码之前,先建立自建表ZCHENH006,表中包含两个关键字段 BELNR(地区编码),SDESC(地区描述). 编码规则参考:身份证前六位地区编码规则,可参考我另外一篇Blog导入系统 ...
- SSM框架整合的其它方式
---------------------siwuxie095 SSM 框架整合的其它方式 1.主要是整合 Spring ...
- 回忆Partition算法及利用Partition进行快排
一.Partiton算法 Partiton算法的主要内容就是随机选出一个数,将这个数作为中间数,将大于它的排在它右边,小于的排在左边(无序的). int partition (int arr[],in ...
- [leetcode]51. N-QueensN皇后
The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens ...
- jQuery的介绍
01-jQuery的介绍 1.为什么要使用jQuery 在用js写代码时,会遇到一些问题: window.onload 事件有事件覆盖的问题,因此只能写一个事件. 代码容错性差. 浏览器兼容性问题 ...
- Django model进阶
Django-model进阶 QuerySet 可切片 使用Python 的切片语法来限制查询集记录的数目 .它等同于SQL 的LIMIT 和OFFSET 子句. >>> Ent ...
- MySQL开发——【字符集、校对集】
字符集 查看MySQL中的字符集 基本语法: show character set; 查看MySQL中的默认字符集 基本语法: show variables like ‘character_set%’ ...