网站被攻击,恶意ip疯狂访问怎么办?

1
火车票抢票软件大家都知道 , 相信大多数人都用过 , 什么智行 , 携程 , 飞猪 , 都有抢票功能 , 尤其是在节假日 , 大家为了抢票 , 纷纷各种转发 , 加钱 , 升级自己的抢票级别 , 其实背后的机制就是疯狂的调12306的订票接口 , 调的频率高 , 抢到票的几率就高 , 12306也发表声明 , 这种疯狂调接口的平台12306已经做了限制 。
做限制 , 无外乎就是限制ip访问频率 , 要不就是控制接口最大并发量 , 有些恶意攻击就是疯狂调接口 , 把你接口调的欲哭无泪 , 下面就来写一个限制ip访问的机制 。
2
这个限制ip访问机制就是通过控制ip一段时间访问次数如果超过这个次数 , 就将该ip拉入黑名单一段时间 , 等限制时间结束 , 再移出黑名单 。
首先我们创建一个监听器 , 这个监听器的作用就是在初始化项目时进行一些基础信息的创建 。
@JAVAx.servlet.annotation.WebListenerpublic class WebListener implements ServletContextListener { public void contextInitialized(ServletContextEvent servletContextEvent) { Logger logger = LoggerFactory.getLogger(WebListener.class); logger.info("Project初始化成功"); ServletContext context = servletContextEvent.getServletContext(); // IP存储器 Map<String, Long[]> ipMap = new ConcurrentHashMap<String, Long[]>(); context.setAttribute("ipMap", ipMap); // 限制IP存储器:存储被限制的IP信息 Map<String, Long> limitedIpMap = new HashMap<String, Long>(); context.setAttribute("limitedIpMap", limitedIpMap); logger.info("ipmap:"+ipMap.toString()+";limitedIpMap:"+limitedIpMap.toString()+"初始化成功 。。。。。"); } public void contextDestroyed(ServletContextEvent servletContextEvent) { }}这个监听器的作用就是初始化一个Ip存储器和限制IP存储器 , Ip存储器就是将请求来的ip进行存储 , 限制IP存储器就是将被拉入黑名单的ip进行存储 。
Ip存储器创建好之后就是要创建过滤器 , 我们实现ip限制就是依靠过滤器进行实现 , 创建一个过滤器 , 设置对所有请求进行拦截 。
@WebFilter(urlPatterns = "/*")public class IpFilter implements Filter {这个@WebFilter注解就是设置拦截器的拦截范围
接着我们就主要是在doFilter方法里实现我们的ip限制功能 , ip限制通过默认限制时间 , ip连续访问阀值 , 用户最小访问安全时间这三点进行灵活控制 。
public class IpFilter implements Filter { /** * 默认限制时间(单位:ms) */ private static final long LIMITED_TIME_MILLIS = 60 * 1000; /** * 用户连续访问最高阀值 , 超过该值则认定为恶意操作的IP , 进行限制 */ private static final int LIMIT_NUMBER = 5; /** * 用户访问最小安全时间 , 在该时间内如果访问次数大于阀值 , 则记录为恶意IP , 否则视为正常访问 */ private static final long MIN_SAFE_TIME = 60 * 1000; private FilterConfig config; public void init(FilterConfig config) throws ServletException { this.config = config; }public class IpFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { ServletContext context = config.getServletContext(); // 获取限制IP存储器:存储被限制的IP信息 Map<String, Long> limitedIpMap = (Map<String, Long>) context.getAttribute("limitedIpMap"); // 过滤受限的IP filterLimitedIpMap(limitedIpMap); /** * @param limitedIpMap * @Description 过滤受限的IP , 剔除已经到期的限制IP */ private void filterLimitedIpMap(Map<String, Long> limitedIpMap) { if (limitedIpMap == null) { return; } Set<String> keys = limitedIpMap.keySet(); Iterator<String> keyIt = keys.iterator(); long currentTimeMillis = System.currentTimeMillis(); while (keyIt.hasNext()) { long expireTimeMillis = limitedIpMap.get(keyIt.next()); if (expireTimeMillis <= currentTimeMillis) { keyIt.remove(); } } }首先我们需要获取ip存储器 , 然后对当前的限制ip进行过滤 , 看是否有已经超过默认时间的ip,将其从限制ip中移除 。
// 获取用户IP String ip = IpUtil.getIpAddr(request); System.err.println("ip:" + ip); // 判断是否是被限制的IP , 如果是则跳到异常页面 if (isLimitedIP(limitedIpMap, ip)) { long limitedTime = limitedIpMap.get(ip) - System.currentTimeMillis(); // 剩余限制时间(用为从毫秒到秒转化的一定会存在些许误差 , 但基本可以忽略不计) request.setAttribute("remainingTime", ((limitedTime / 1000) + (limitedTime % 1000 > 0 ? 1 : 0))); //request.getRequestDispatcher("/error/overLimitIP").forward(request, response); System.err.println("ip访问过于频繁:" + ip + "当前时间" + System.currentTimeMillis()); return; }


推荐阅读