美团面试:接口被恶意狂刷,怎么办?

news2024/9/29 11:32:40

如果Java接口被恶意狂刷,我们一般可以采取以下措施:

用TimeStamp (兵不厌诈)

比如给客户端提供一个timestamp参数,值是13位的毫秒级时间戳,可以在第12位或者13位做一个校验位,通过一定的算法给其他12位的值做一个校验。

举例:现在实际时间是 1684059940123,我通过前12位算出来校验位是9,参数则把最后一位改成9,即1684059940129,值传到服务端后通过前十二位也可以算出来值,来判断这个时间戳是不是合法的。

根据前面12位计算校验位,可以使用以下代码实现:

/**
 * 计算timestamp的校验位
 */
private int calculateCheckDigit(long timestamp) {
    int sum = 0;
    for (int i = 0; i < TIMESTAMP_DIGITS - 1; i++) {
        char c = String.valueOf(timestamp).charAt(i);
        sum += Integer.parseInt(String.valueOf(c));
    }
    return sum % 10;
}

在上述代码中,calculateCheckDigit方法接收一个13位毫秒级时间戳作为参数,返回该时间戳的校验位。具体地,该方法会循环遍历时间戳的前12位,并将这些数字相加。最后,计算总和的个位数并返回。

例如:如果时间戳为1684059940123,则该方法计算出来的校验位为9。

但是如果黑客翻客户端代码,就知道校验位的情况了。因为这个校验逻辑客户端必然也有一份。如果客户端代码是公开的,那么攻击者可以通过研究客户端代码得到校验位计算的方式。这样一来,攻击者就有可能伪造出带有正确校验位的timestamp参数,从而绕过Java接口的限流和安全机制。

因此,该方案主要适用于需要简单防范一些低强度攻击的场景,例如防范垃圾请求或非法爬虫等。对于高强度攻击,建议采取更为复杂的验证策略,例如使用OAuth2授权、IP白名单、签名算法等。同时,建议客户端和服务端在通信过程中使用HTTPS协议进行加密,防止数据被窃听或篡改。

加强安全认证

@RequestMapping("/api/login")
public String login(@RequestParam("username") String username, @RequestParam("password") String password){
    if(!checkUser(username, password)){
        return "用户名或密码错误";
    }
    String token = getToken();
    saveToken(token);
    return token;
}

private boolean checkUser(String username, String password){
    //校验用户是否合法
}

private String getToken(){
    //生成token
}

private void saveToken(String token){
    //保存token
}

在上述代码中,当用户调用login接口时,需要提供用户名和密码。此时会进行用户校验,若校验失败则返回错误信息,否则生成token并保存,最终返回给用户。

生成Token的作用是为了在接口请求时验证用户身份。具体来说,当用户第一次登录系统后,该接口可以根据用户信息生成一个Token字符串,并将其保存至服务端或客户端。当此用户访问其他需要鉴权的接口时,需要在请求头中带上这个Token字符串,以便服务器进行身份验证。

对于Java接口被恶意狂刷问题,Token的作用是防止非法请求。由于Token是由服务端生成的,攻击方无法自己生成有效的Token,因此只有拥有合法Token的用户才能成功调用相关接口。

关于Token的验证,可以通过拦截器实现。拦截器可以在接口调用前检查请求头中是否包含合法的Token,并验证Token是否过期、是否被篡改等。如果Token验证失败,则返回错误信息并拦截该请求。

下面是生成Token和使用拦截器的示例代码:

// 生成Token
private String generateToken(User user) {
    // 基于用户名、密码、时间戳等信息生成Token字符串
}

// 鉴权拦截器
public class AuthInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object handler) throws Exception {
        String token = request.getHeader("Authorization");
        if (token == null || !checkToken(token)) {
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            return false;
        }
        return true;
    }

    private boolean checkToken(String token) {
        // 验证Token是否合法,是否过期等
    }
}

在上述代码中,generateToken方法用于生成Token字符串,并保存至服务端或客户端。AuthInterceptor类是拦截器类,用于检查请求头中的Token是否合法。如果Token验证失败,则返回401错误码并拦截该请求。需要注意的是,在使用该拦截器时,需要将其注册到Spring MVC框架中。

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private AuthInterceptor authInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor).addPathPatterns("/api/**");
    }
}

以上代码是将AuthInterceptor拦截器注册到Spring MVC框架中,使其生效。其中,"/api/**"表示拦截所有以"/api"开头的接口。

IP封禁

public class IpFilter extends OncePerRequestFilter {
    private static final Set<String> IP_SET = new HashSet<>();

    static {
        IP_SET.add("192.168.1.100");
        IP_SET.add("127.0.0.1");
        //添加其他需要封禁的IP
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        String ipAddress = request.getRemoteAddr();
        if(IP_SET.contains(ipAddress)){
            response.setStatus(HttpStatus.FORBIDDEN.value());
            return;
        }

        filterChain.doFilter(request, response);
    }
}

在上述代码中,通过IpFilter过滤器来阻止特定的IP地址访问接口。其中,IP_SET为需要封禁的IP地址集合。

接口限流

public class RateLimitInterceptor extends HandlerInterceptorAdapter {
    private static final int DEFAULT_RATE_LIMIT_COUNT = 100; //默认每秒允许100次请求
    private static final int DEFAULT_RATE_LIMIT_TIME_WINDOW = 1000; //默认时间窗口为1秒
    private Map<String, Long> requestCountMap = new ConcurrentHashMap<>();
    private int rateLimitTimeWindow;
    private int rateLimitCount;

    public RateLimitInterceptor(){
        this(DEFAULT_RATE_LIMIT_TIME_WINDOW, DEFAULT_RATE_LIMIT_COUNT);
    }

    public RateLimitInterceptor(int timeWindow, int limitCount){
        this.rateLimitTimeWindow = timeWindow;
        this.rateLimitCount = limitCount;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        String key = request.getRemoteAddr() + ":" + request.getRequestURI();
        long now = System.currentTimeMillis();
        if(requestCountMap.containsKey(key)){
            long last = requestCountMap.get(key);
            if(now - last < rateLimitTimeWindow){
                if(requestCountMap.get(key) >= rateLimitCount){
                    response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
                    return false;
                }
                requestCountMap.put(key, requestCountMap.get(key) + 1);
            }else{
                requestCountMap.put(key, now);
            }
        }else{
            requestCountMap.put(key, now);
        }
        return true;
    }
}

在上述代码中,通过RateLimitInterceptor拦截器实现接口限流功能。默认情况下,每秒钟最多允许100次请求。如果当秒内请求数超过限制,则返回状态码429。

日志监控

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    throws IOException, ServletException {
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    HttpServletResponse httpResponse = (HttpServletResponse) response;
    String requestURI = httpRequest.getRequestURI();

    try {
        log.info("Request Received. URI: {}", requestURI);
        chain.doFilter(request, response);
    } catch(Exception e) {
        log.error("Exception occurred while processing request. URI: {}", requestURI, e);
        throw e;
    } finally {
        log.info("Request Completed. URI: {} Response Status: {}", requestURI, httpResponse.getStatus());
    }
}

在上述代码中,通过Filter过滤器来实现日志监控。当请求进入时记录请求URI,当请求结束时记录响应状态码,如此可及时发现异常情况。

升级硬件设备

如果服务器无法承受恶意攻击,可以通过升级硬件设备来增加服务器的承载能力。例如,可以增加CPU或内存等硬件资源,降低服务器的响应时间。

通知相关部门

当Java接口被恶意狂刷时,及时通知相关管理人员或安全团队是非常重要的。他们可以采取更加有效的措施,如封禁IP地址、加强认证机制等,从而保障接口的安全。以下是一些示例代码:

//发送邮件通知相关部门
public void sendNotificationEmail(String subject, String content, String... recipients) {
    SimpleMailMessage message = new SimpleMailMessage();
    message.setFrom("sender@example.com");
    message.setTo(recipients);
    message.setSubject(subject);
    message.setText(content);
    
    mailSender.send(message);
}

//发送短信通知相关部门
public void sendNotificationSMS(String phoneNumber, String content) {
    //调用第三方短信API发送短信
}

总结

1.大部分情况,token校验+拦截器已然足够,敏感接口再加限流,这也是大部分企业的做法。

2.简单场景用TimeStamp就行了,对于大部分机器人恶意访问,他是不可能去看你代码的。

3.尽量不要封禁IP,防止误伤,因为很多小区住户往往是局域网,很多人就是共用一个IP的。

4.更狠的方法是,模仿那种”请选择图片中的汽车“的做法,反向薅羊毛,嗯,大家应该明白其中的意思。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/570706.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker实战2-发布后端Java项目

有了上篇Docker实战1-发布前端Vue项目的经验&#xff0c;发布后端就轻车熟路了。 1 准备文件 java打包 运行maven的package,生成jar文件&#xff0c;target/dsm-service-1.0-SNAPSHOT.jar DockerFile # Docker image for springboot file run FROM openjdk:11.0.11-jdk-sli…

【JavaSE】Java基础语法(十二):ArrayList

文章目录 1. ArrayList的构造方法和添加方法2. ArrayList类常用方法3. ArrayList存储学生对象并遍历 集合和数组的区别 : 共同点&#xff1a;都是存储数据的容器不同点&#xff1a;数组的容量是固定的&#xff0c;集合的容量是可变的 1. ArrayList的构造方法和添加方法 ArrayL…

2023亚马逊云科技游戏开发者大会从技术角度探索游戏的广阔边界

自上世纪五十年代诞生以来&#xff0c;电子游戏产业蓬勃发展&#xff0c;这与人类想象力的解放有着无比紧密地联系。伴随着全球游戏市场竞争的加剧&#xff0c;“游戏人”面临着很多全新的挑战。因此&#xff0c;2023亚马逊云科技游戏开发者大会不仅带来了最新的游戏行业举措&a…

基于多智能体深度强化学习的体系任务分配方法

源自&#xff1a;指挥与控制学报 作者&#xff1a;林萌龙, 陈涛, 任棒棒, 张萌萌, 陈洪辉 摘 要 1 背景 1.1 集中式决策VS分布式决策 图1集中式决策示意图 1.2 多智能体强化学习 2 问题描述 2.1 场景描述 图2分布式决策场景下的体系任务分配 2.2 状态空间、动作…

PyTorch-DataLoader

DataLoader&#xff1a;从Dataset中取数据&#xff0c;怎么取&#xff0c;每次取多少可以由DataLoader中的参数进行设定&#xff0c;并将数据加载到神经网络中。 dataloader.py import torchvision from torch.utils.data import DataLoader from torch.utils.tensorboard im…

Python框架比较:Django、Flask和Pyramid三者的优缺点和应用场景

第一章&#xff1a;引言 在当今快节奏的软件开发行业中&#xff0c;选择合适的开发框架对于开发人员来说至关重要。Python作为一种流行的编程语言&#xff0c;拥有众多强大的框架&#xff0c;其中包括Django、Flask和Pyramid。本文将比较这三个Python框架的优缺点和应用场景&a…

企业级低代码开发,迈向企业数字化时代

当下&#xff0c;随着科技的快速发展&#xff0c;软件开发的成本不断降低&#xff0c;越来越多的人可以参与到软件开发的过程中。但是在这个过程中&#xff0c;我们也发现了一个问题&#xff0c;就是软件开发的成本越来越高。传统的开发模式需要投入大量人力物力&#xff0c;而…

旅游信息推荐系统

文章目录 旅游信息推荐系统一、系统演示二、项目介绍三、系统运行界面图四、系统部分功能截图五、部分代码展示六、底部获取源码 旅游信息推荐系统 一、系统演示 旅游信息推荐系统 二、项目介绍 数据库版本&#xff1a; mysql8.0 数据库可视化工具&#xff1a; navicat 服务器…

新技术越来越多,作为程序员,我们应该怎么规划职业生涯? | 社区征文

随着科技的不断进步&#xff0c;新技术不断涌现&#xff0c;对程序员的要求也在不断提高。作为一名程序员&#xff0c;要想在这个竞争激烈的行业中立足&#xff0c;就需要制定一份明确的职业规划&#xff0c;不断学习和掌握新技术&#xff0c;提升自己的职业能力和竞争力。 确定…

自古以来,反射也是兵家必争之地

成文耗时1小时&#xff0c;阅读5min&#xff0c;有用指数5颗星。 这几天收到一个战术性需求&#xff0c;将一大坨字段序列化为特定格式的字符串。 大概是下表&#xff1a; 序号字段名描述是否必填0logVersion日志版本是1productName产品是2serviceName服务是.........25extend3…

手写Spring源码(简化版)

导航&#xff1a; 【Java笔记踩坑汇总】Java基础进阶JavaWebSSMSpringBoot瑞吉外卖SpringCloud黑马旅游谷粒商城学成在线MySQL高级篇设计模式牛客面试题 参考视频&#xff1a; 周瑜大都督手写模拟Spring_哔哩哔哩 源码&#xff1a; https://gitee.com/vincewm/spring-master 目…

windows自动保存git密码

Windows平台在使用Git的时候经常会出现反复输入密码&#xff0c;生成密钥对的时候如果设置了密码&#xff0c;那么每次使用时都会要求输入密码&#xff0c;那可以通过下面的方式解决。 1. 配置ssh自动启动 管理员启动终端 Set-Service ssh-agent -StartupType Auto # 设置为…

C语言实现分数求和

代码&#xff1a; // 计算1/1 - 1/2 1/3 - 1/4 ...1/99 - 1/100的值 // 计算1/1 - 1/2 1/3 - 1/4 ...1/99 - 1/100的值 int main() {int i 0;double sum 0.0;int flag 1;for (i 1; i < 100; i) {sum sum flag*(1.0 / i);flag -flag;}printf("%lf\n", su…

Caffeine 本地高速缓存工具类

目录 Caffeine工具类方式 SpringBoot 整合 Caffeine 缓存 &#xff08;SpringCache模式&#xff09; 驱逐策略 开发使用 Caffeine是一种高性能的缓存库&#xff0c;是基于Java 8的最佳&#xff08;最优&#xff09;缓存框架&#xff0c;性能各方面优于guava。 Caffeine工具…

脉蜂:Django + Flutter 开发的进销存管理系统【已开源】

项目说明 小规模零售&#xff08;包括电商&#xff09;跟大规模零售企业的差别在哪里呢&#xff1f; 以我当前的认知来看&#xff0c;小规模零售跟大规模零售企业的差别更多的是在供应链管理、进销存管控上面产生的。如果有一个工具&#xff0c;能够帮他们减少这方面的差异&…

我们拆了一款Tof+AI避障的扫地机,小米铁蛋铁大机器人同款

追觅W10 Pro是2022年初推出的新品&#xff0c;相较前一代W10&#xff0c;两者间最大的区别是将LDS避障升级为了TofAI避障&#xff0c;扫地机本体前脸像给W10开了“大眼特效”的传感器和摄像头就是机械避障升级的最佳佐证。 在外观上扫地机还是延续了以往的设计&#xff0c;顶部…

ReactRouterDom-v5v6用法与异同

本文作者系360奇舞团前端开发工程师 简介&#xff1a; React Router Dom是React.js中用于实现路由功能的常用库。在React应用中&#xff0c;路由可以帮助我们管理页面之间的导航和状态&#xff0c;并实现动态加载组件。本文将深入探讨React Router Dom的两个主要版本&#xff1…

​一文学会iOS画中画浮窗

本文字数&#xff1a;11934字 预计阅读时间&#xff1a;40分钟 背景 之前有看到有人用画中画实现时分秒的计时&#xff0c;顺手收藏了&#xff0c;一直没来及看。最近使用《每日英语听力》&#xff0c;突然发现它用画中画实现了听力语句的显示&#xff0c;顿时来了兴趣&#xf…

超线程技术

超线程&#xff08;HT, Hyper-Threading&#xff09;是英特尔研发的一种技术&#xff0c;于2002年发布。超线程技术原先只应用于Xeon 处理器中&#xff0c;当时称为“Super-Threading”。之后陆续应用在Pentium 4 HT中。早期代号为Jackson。 [1] 通过此技术&#xff0c;英特尔实…