面试官:你讲下接口防重放如何处理?

2024-06-11 17:12
文章标签 接口 处理 面试官 防重

本文主要是介绍面试官:你讲下接口防重放如何处理?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

我们的API接口都是提供给第三方服务/客户端调用,所有请求地址以及请求参数都是暴露给用户的。

我们每次请求一个HTTP请求,用户都可以通过F12,或者抓包工具fd看到请求的URL链接,然后copy出来。这样是非常不安全的,有人可能会恶意的刷我们的接口,那这时该怎么办呢?防重放攻击就出来了。

什么是防重放攻击

我们以掘金文章点赞为例。当我点赞之后,H5会发送一个请求给到掘金后端服务器,我可以通过f12看到完整的请求参数,包括url,param等等,然后我可以通过copy把这个请求给copy出来,那么我就可以做到一个放重放攻击了。

具体如下。我们可以看到,服务端返回的是重复点赞,也就是掘金并没有做我们所谓世俗意义上的放重放攻击。掘金通过查询数据库(推测item_id是唯一索引值),来判断是否已经点赞然后返回前端逻辑。

那么什么是我们理解的放重放呢

简单来说就是,前端和客户端约定一个算法(比如md5),通过加密时间戳+传入字段。来起到防止重复请求的目的。然后这个时间戳可以设定为30秒,60秒过期。

那么如果30秒,有人不断刷我们的接口怎么办。我们还可以新加一个字段为nonceKey,30秒内随机不重复。这个字段存放在Redis,并且30秒过期。如果下一次请求nonceKey还在redis,我就认为是重复请求,拒绝即可。

算法实现

  1. 首先定义一个全局拦截器

@Component
public class TokenInterceptor implements HandlerInterceptor {@Autowiredprivate StringRedisTemplate redisService;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {String timestamp = request.getParameter("timestamp");String token = request.getParameter("token");if (timestamp == null || token == null) {return false;}TreeMap<String, String> map = new TreeMap<>();Enumeration<String> parameterNames = request.getParameterNames();while (parameterNames.hasMoreElements()) {String str = parameterNames.nextElement();if (StringUtils.equals(str, "token")) {continue;}map.put(str, request.getParameter(str));}return SecretUtils.extractSecret(redisService, timestamp, token, map);}
}

  1. 定义具体的算法实现

public class SecretUtils {private static final long NONCE_DURATION = 60 * 1000L;private static final String SALT = "salt"; // 注意这块加盐public static boolean extractSecret(StringRedisTemplate redisService, String timestamp, String token, TreeMap<String, String> map) {if (StringUtils.isEmpty(timestamp) || StringUtils.isEmpty(token)) {return false;}long ts = NumberUtils.toLong(timestamp, 0);long now = System.currentTimeMillis();if ((now - ts) > SecretUtils.NONCE_DURATION || ts > now) {return false;}StringBuilder sb = new StringBuilder();map.put(SALT, SALT);for (Map.Entry<String, String> entry : map.entrySet()) {String key = entry.getKey();String value = entry.getValue();if (sb.length() > 0) {sb.append("&");}sb.append(key).append("=").append(value);}String targetToken = DigestUtils.md5DigestAsHex(sb.toString().getBytes());if (!token.equals(targetToken)) {return false;}String s = redisService.opsForValue().get(timestamp);if (StringUtils.isNotEmpty(s)) {return false;} else {redisService.opsForValue().set(timestamp, timestamp, NONCE_DURATION, TimeUnit.MILLISECONDS);}return true;}}

前端会通过我们事先约定好的算法以及方式,将字符串从小到大进行排序 + timestamp,然后md5进行加密生成token传给后端。后端根据算法+方式来校验token是否有效。

如果其中有人修改了参数,那么token就会校验失败,直接拒绝即可。如果没修改参数,timestamp如果大于60s,则认为是防重放攻击,直接拒绝,如果小于30s,则将nonceKey加入到redis里面,这里nonceKey用的是timestamp字段,如果不存在则第一次请求,如果存在,则直接拒绝即可。

通过这么简单的一个算法,就可以实现防重放攻击了。

Q&A

Q:客户端和服务端生成的时间戳不一致怎么办

A:客户端和服务端生成的是时间戳,不是具体的时间,时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数

Q:HTTPS数据加密是否可以防止重放攻击

A:不可以。https是在传输过程中保证了加密,也就是说如果中间人,获取到了请求,他是无法解开传输的内容的。

举个最简单的例子,上课和同学传纸条的时候,为了不让中间给递纸条的人看到或者修改,可以在纸条上写成只有双方能看明白密文,这样递纸条的过程就安全了,传纸条过程中的人就看不懂你的内容了。但是如果给你写纸条的人要搞事情,那就是加密解决不了的了。这时候就需要放重放来解决了。

Q:防重放攻击是否有用,属于脱裤子放屁

A:个人感觉有一点点吧。比如防重放攻击的算法+加密方式其实大多数用的都是这些,其实攻击人很容易就能猜到token生成的方式,比如timestamp + 从小到大排序。因此我们加入了salt来混淆视听,这个salt需要前端、客户端安全的存储,不能让用户知道,比如js混淆等等。但其实通过抓包,js分析还是很容易能拿到的。但无形中增加了攻击人的成本,比如网易云登录的js加密类似。

Q:做了防重放,支付,点赞等是否不需要做幂等了

A:需要。最重要的幂等,一定要用数据库来实现,比如唯一索引。其他都不可相信。

最后

以我个人的理解。防重放用处不大,其他安全措施,比如非对称的RSA验签更加有效。就算用户拿到了请求的所有信息,你的接口也一定要做幂等的,尤其是像支付转账等高危操作,幂等才是最有用的防线。而且防重发生成token的算法,大家都这样搞,攻击者怎么可能不知道呢?这点我不太理解。

文章转载自:程序员博博

原文链接:https://www.cnblogs.com/wenbochang/p/18240697

体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构

这篇关于面试官:你讲下接口防重放如何处理?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1051785

相关文章

浅析Java中如何优雅地处理null值

《浅析Java中如何优雅地处理null值》这篇文章主要为大家详细介绍了如何结合Lambda表达式和Optional,让Java更优雅地处理null值,感兴趣的小伙伴可以跟随小编一起学习一下... 目录场景 1:不为 null 则执行场景 2:不为 null 则返回,为 null 则返回特定值或抛出异常场景

深入理解Apache Kafka(分布式流处理平台)

《深入理解ApacheKafka(分布式流处理平台)》ApacheKafka作为现代分布式系统中的核心中间件,为构建高吞吐量、低延迟的数据管道提供了强大支持,本文将深入探讨Kafka的核心概念、架构... 目录引言一、Apache Kafka概述1.1 什么是Kafka?1.2 Kafka的核心概念二、Ka

resultMap如何处理复杂映射问题

《resultMap如何处理复杂映射问题》:本文主要介绍resultMap如何处理复杂映射问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录resultMap复杂映射问题Ⅰ 多对一查询:学生——老师Ⅱ 一对多查询:老师——学生总结resultMap复杂映射问题

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

C#使用SQLite进行大数据量高效处理的代码示例

《C#使用SQLite进行大数据量高效处理的代码示例》在软件开发中,高效处理大数据量是一个常见且具有挑战性的任务,SQLite因其零配置、嵌入式、跨平台的特性,成为许多开发者的首选数据库,本文将深入探... 目录前言准备工作数据实体核心技术批量插入:从乌龟到猎豹的蜕变分页查询:加载百万数据异步处理:拒绝界面

Springboot处理跨域的实现方式(附Demo)

《Springboot处理跨域的实现方式(附Demo)》:本文主要介绍Springboot处理跨域的实现方式(附Demo),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录Springboot处理跨域的方式1. 基本知识2. @CrossOrigin3. 全局跨域设置4.

go中空接口的具体使用

《go中空接口的具体使用》空接口是一种特殊的接口类型,它不包含任何方法,本文主要介绍了go中空接口的具体使用,具有一定的参考价值,感兴趣的可以了解一下... 目录接口-空接口1. 什么是空接口?2. 如何使用空接口?第一,第二,第三,3. 空接口几个要注意的坑坑1:坑2:坑3:接口-空接口1. 什么是空接

python+opencv处理颜色之将目标颜色转换实例代码

《python+opencv处理颜色之将目标颜色转换实例代码》OpenCV是一个的跨平台计算机视觉库,可以运行在Linux、Windows和MacOS操作系统上,:本文主要介绍python+ope... 目录下面是代码+ 效果 + 解释转HSV: 关于颜色总是要转HSV的掩膜再标注总结 目标:将红色的部分滤

Python实现自动化接收与处理手机验证码

《Python实现自动化接收与处理手机验证码》在移动互联网时代,短信验证码已成为身份验证、账号注册等环节的重要安全手段,本文将介绍如何利用Python实现验证码的自动接收,识别与转发,需要的可以参考下... 目录引言一、准备工作1.1 硬件与软件需求1.2 环境配置二、核心功能实现2.1 短信监听与获取2.

Python使用date模块进行日期处理的终极指南

《Python使用date模块进行日期处理的终极指南》在处理与时间相关的数据时,Python的date模块是开发者最趁手的工具之一,本文将用通俗的语言,结合真实案例,带您掌握date模块的六大核心功能... 目录引言一、date模块的核心功能1.1 日期表示1.2 日期计算1.3 日期比较二、六大常用方法详