赞
踩
前段时间公司服务器被攻击,防火墙显示一个南京的ip一天访问接口20w+次,一下子把数据库cpu搞到00%,临时解决办法是把该ip通过防火墙访问策略禁止访问了,为了防止后期还有恶意攻击,我们在项目中新增一个拦截器,根据用户访问的ip和资源请求的url限制其访问频率。
通过拦截器,我们设置了1分钟内同一个ip和ur如果请求超过25次就提醒超过了限定的次数
- package com.brickdog.filter;
-
-
- import com.brickdog.common.utils.CacheUtils;
- import com.brickdog.common.utils.RequestLimit.HttpUtil;
- import com.brickdog.common.utils.RequestLimit.RequestLimitException;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.stereotype.Component;
- import org.springframework.web.servlet.HandlerInterceptor;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
-
-
-
- @Slf4j
- @Component
- public class RequestLimitInterceptor implements HandlerInterceptor {
-
-
- @Override
- public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws RequestLimitException {
- try {
-
-
- Integer limit_count = 25;
- Integer limit_time = 1000 *60;
-
- String ip = HttpUtil.getIpByRequest(httpServletRequest);
- String url = httpServletRequest.getRequestURL().toString();
- String key = "req_limit_".concat(url).concat(ip);
-
- String cache = (String)CacheUtils.get(key);
- if (null == cache) {
- String value = "1_" + System.currentTimeMillis();
- CacheUtils.put(key,value,limit_time);
- } else {
- String value = (String) cache;
- String[] s = value.split("_");
- int count = Integer.parseInt(s[0]);
-
- if (count > limit_count) {
- log.info("用户IP[{}], 访问地址[{}], 超过了限定的次数[{}]", ip, url, limit_count);
- throw new RequestLimitException();
- }
-
- value = (count + 1) + "_" + s[1];
- long last = limit_time - (System.currentTimeMillis() - Long.parseLong(s[1]));
- if (last > 0) {
- CacheUtils.put(key,value,limit_time);
- }
- }
-
-
- } catch (RequestLimitException e) {
- throw e;
- } catch (Exception e) {
- log.error("发生异常", e);
- }
- return true;
- }
- }
-
- package com.brickdog.config;
-
-
- import com.brickdog.filter.AuthHandlerInterceptor;
- import com.brickdog.filter.RequestLimitInterceptor;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
- import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
- import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-
- /**
- * @author brickdog
- * @version 1.0
- * @create 2022/2/4 21:24
- */
- @Configuration
- public class AuthConfigurer implements WebMvcConfigurer {
-
- @Autowired
- RequestLimitInterceptor requestLimitInterceptor;
-
- @Override
- public void addInterceptors(InterceptorRegistry registry) {
-
- registry.addInterceptor(requestLimitInterceptor);
- }
-
- }
- package com.brickdog.common.utils;
-
- import java.util.Map;
- import java.util.concurrent.*;
-
- public class CacheUtils {
-
- // 键值对集合
- private final static Map<String, Entity> map = new ConcurrentHashMap<>();
- // 定时器线程池, 用于清除过期缓存
- private final static ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
-
- /**
- * 添加缓存
- */
- public synchronized static void put(String key, Object data) {
- CacheUtils.put(key, data, 0);
- }
-
- /**
- * 添加缓存
- * 过期时间: 单位毫秒, 0表示无限长
- */
- public synchronized static void put(String key, Object data, long expire) {
- // 清除原键值对
- CacheUtils.remove(key);
- // 设置过期时间
- if (expire > 0) {
- Future future = executor.schedule(() -> {
- // 过期后清除该键值对
- synchronized (CacheUtils.class) {
- map.remove(key);
- }
- }, expire, TimeUnit.MILLISECONDS);
- map.put(key, new Entity(data, future));
- } else {
- // 不设置过期时间
- map.put(key, new Entity(data, null));
- }
- }
-
- /**
- * 读取缓存
- */
- public synchronized static Object get(String key) {
- Entity entity = map.get(key);
- return entity == null ? null : entity.getValue();
- }
-
- /**
- * 读取缓存
- * clazz 值类型
- */
- public synchronized static <T> T get(String key, Class<T> clazz) {
- return clazz.cast(CacheUtils.get(key));
- }
-
- /**
- * 清除指定缓存
- * 返回值为指定key的value
- */
- public synchronized static Object remove(String key) {
- // 清除指定缓存数据
- Entity entity = map.remove(key);
- if (entity == null)
- return null;
- // 清除指定键值对定时器
- Future future = entity.getFuture();
- if (future != null)
- future.cancel(true);
- return entity.getValue();
- }
-
- /**
- * 清除所有缓存
- */
- public synchronized static void removeAll() {
- map.clear();
- }
-
- /**
- * 查询当前缓存的键值对数量
- */
- public synchronized static int size() {
- return map.size();
- }
-
- /**
- * 缓存实体类
- */
- private static class Entity {
- // 键值对的value
- private Object value;
- // 定时器的future
- private Future future;
-
- /**
- * 创建实体类
- */
- public Entity(Object value, Future future) {
- this.value = value;
- this.future = future;
- }
-
- /**
- * 获取value值
- */
- public Object getValue() {
- return value;
- }
-
- /**
- * 获取future对象
- */
- public Future getFuture() {
- return future;
- }
- }
-
- }
- <!-- 日志 -->
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <version>1.7.30</version>
- </dependency>
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <version>1.18.16</version>
- </dependency>
- <!-- 日志 -->
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。