写了一个小站点,帮助我们学校的同学应付考试。当然也赚了一点钱…但就是有一些调皮的同学过来攻击我。无脑扫描我的web接口,之前用的别人的内网穿透的工具,因为本身价格不是很高,所以他对 TCP连接数有分钟限制,导致了我的站点无法被正常访问。但是我拦截了高频率访问,只是限制了他爬取我的web资源,并不能根本解决TCP连接限制这个问题,后来,我买了阿里云,自己搭建内网穿透。问题解决。

好了废话不多说,直接进入主题。
开启拦截的整个过程:
访问 站点—记录ip—若存在则,计算访问速度是否达到阈值,达到则拉黑名单,直接返回JSON字符串。若不存在,加入该ip。
接下来直接贴代码:

1.配置过滤器

/*** @Auther: raven* @Date: 2019/12/9 14:04* @Description:*/import util.IpUtils;import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** 自定义过滤器,用来判断IP访问次数是否超限* 如果前台用户访问网站的频率过快(达到超过50次/秒),则判定该ip恶意刷新操作,* 限制该IP的访问,1小时后自己解除限制** @author wukaikai**/
@WebFilter(urlPatterns="/*")
public class IpFilter implements Filter{/*** 默认限制时间(单位:ms)*/private static final long LIMITED_TIME_MILLIS = 60 * 60 * 1000;/*** 用户连续访问最高阀值,超过该值则认定为恶意操作的IP,进行限制*/private static final int LIMIT_NUMBER = 100;/*** 用户访问最小安全时间,在该时间内如果访问次数大于阀值,则记录为恶意IP,否则视为正常访问*/private static final int MIN_SAFE_TIME = 5000;private FilterConfig config;@Overridepublic void init(FilterConfig filterConfig) throws ServletException {this.config = filterConfig;    //设置属性filterConfig}/* (non-Javadoc)* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)*/@SuppressWarnings("unchecked")@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;ServletContext context = config.getServletContext();// 获取限制IP存储器:存储被限制的IP信息Map<String, Long> limitedIpMap = (Map<String, Long>) context.getAttribute("limitedIpMap");// 过滤受限的IPfilterLimitedIpMap(limitedIpMap);// 获取用户IPString ip = IpUtils.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)));System.err.println("ip访问过于频繁:"+ip);response.setStatus(403);response.setCharacterEncoding("utf-8");    //设置输出内容编码格式response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();out.println("<b>由于您访问过于频繁,被系统自动认定为机器人。1个小时自动解除</b>");return;}// 获取IP存储器Map<String, Long[]> ipMap = (Map<String, Long[]>) context.getAttribute("ipMap");// 判断存储器中是否存在当前IP,如果没有则为初次访问,初始化该ip// 如果存在当前ip,则验证当前ip的访问次数// 如果大于限制阀值,判断达到阀值的时间,如果不大于[用户访问最小安全时间]则视为恶意访问,跳转到异常页面if (ipMap.containsKey(ip)) {Long[] ipInfo = ipMap.get(ip);ipInfo[0] = ipInfo[0] + 1;//  System.out.println("当前第[" + (ipInfo[0]) + "]次访问");if (ipInfo[0] > LIMIT_NUMBER) {Long ipAccessTime = ipInfo[1];Long currentTimeMillis = System.currentTimeMillis();if (currentTimeMillis - ipAccessTime <= MIN_SAFE_TIME) {limitedIpMap.put(ip, currentTimeMillis + LIMITED_TIME_MILLIS);request.setAttribute("remainingTime", LIMITED_TIME_MILLIS);System.err.println("ip访问过于频繁:"+ip);request.getRequestDispatcher("/error/overLimitIP").forward(request, response);return;} else {initIpVisitsNumber(ipMap, ip);}}} else {initIpVisitsNumber(ipMap, ip);//System.out.println("您首次访问该网站");}context.setAttribute("ipMap", ipMap);chain.doFilter(request, response);}@Overridepublic void destroy() {// TODO Auto-generated method stub}/*** @Description 过滤受限的IP,剔除已经到期的限制IP* @param limitedIpMap*/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();}}}/*** @Description 是否是被限制的IP* @param limitedIpMap* @param ip* @return true : 被限制 | false : 正常*/private boolean isLimitedIP(Map<String, Long> limitedIpMap, String ip) {if (limitedIpMap == null || ip == null) {// 没有被限制return false;}Set<String> keys = limitedIpMap.keySet();Iterator<String> keyIt = keys.iterator();while (keyIt.hasNext()) {String key = keyIt.next();if (key.equals(ip)) {// 被限制的IPreturn true;}}return false;}/*** 初始化用户访问次数和访问时间** @param ipMap* @param ip*/private void initIpVisitsNumber(Map<String, Long[]> ipMap, String ip) {Long[] ipInfo = new Long[2];ipInfo[0] = 0L;// 访问次数ipInfo[1] = System.currentTimeMillis();// 初次访问时间ipMap.put(ip, ipInfo);}}

配置监听器初始化一些参数

package config;/*** @Auther: raven* @Date: 2019/12/9 14:04* @Description:*/import java.util.HashMap;
import java.util.Map;import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@WebListener
public class MyApplicationListener implements ServletContextListener {private Logger logger =  LoggerFactory.getLogger(MyApplicationListener.class);@Overridepublic void contextInitialized(ServletContextEvent sce) {logger.info("liting: contextInitialized");System.err.println("MyApplicationListener初始化成功");ServletContext context = sce.getServletContext();// IP存储器Map<String, Long[]> ipMap = new HashMap<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()+"初始化成功。。。。。");}@Overridepublic void contextDestroyed(ServletContextEvent sce) {// TODO Auto-generated method stub}
}

IpUtil类

package util;/*** @Auther: raven* @Date: 2019/12/9 14:06* @Description:*/import javax.servlet.http.HttpServletRequest;
import java.net.*;
import java.util.Enumeration;public class IpUtils {private static final String LOCAL_IP = "127.0.0.1";public static String getIpAddr(HttpServletRequest request) {if (request == null) {return "unknown";}String ip = request.getHeader("x-forwarded-for");if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("X-Forwarded-For");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("X-Real-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}return "0:0:0:0:0:0:0:1".equals(ip) ? LOCAL_IP : ip;}public static boolean internalIp(String ip) {boolean res = false;byte[] addr = textToNumericFormatV4(ip);if (addr != null && ip != null) {res = internalIp(addr) || LOCAL_IP.equals(ip);}return res;}private static boolean internalIp(byte[] addr) {final byte b0 = addr[0];final byte b1 = addr[1];// 10.x.x.x/8final byte SECTION_1 = 0x0A;// 172.16.x.x/12final byte SECTION_2 = (byte) 0xAC;final byte SECTION_3 = (byte) 0x10;final byte SECTION_4 = (byte) 0x1F;// 192.168.x.x/16final byte SECTION_5 = (byte) 0xC0;final byte SECTION_6 = (byte) 0xA8;boolean flag = false;switch (b0) {case SECTION_1:flag = true;break;case SECTION_2:if (b1 >= SECTION_3 && b1 <= SECTION_4) {flag = true;}break;case SECTION_5:if (b1 == SECTION_6) {flag = true;}break;default:break;}return flag;}/*** 将IPv4地址转换成字节*IPv4地址* @param text* @return byte 字节*/public static byte[] textToNumericFormatV4(String text) {if (text.length() == 0) {return null;}byte[] bytes = new byte[4];String[] elements = text.split("\\.", -1);try {long l;int i;switch (elements.length) {case 1:l = Long.parseLong(elements[0]);if ((l < 0L) || (l > 4294967295L))return null;bytes[0] = (byte) (int) (l >> 24 & 0xFF);bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);bytes[3] = (byte) (int) (l & 0xFF);break;case 2:l = Integer.parseInt(elements[0]);if ((l < 0L) || (l > 255L))return null;bytes[0] = (byte) (int) (l & 0xFF);l = Integer.parseInt(elements[1]);if ((l < 0L) || (l > 16777215L))return null;bytes[1] = (byte) (int) (l >> 16 & 0xFF);bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);bytes[3] = (byte) (int) (l & 0xFF);break;case 3:for (i = 0; i < 2; ++i) {l = Integer.parseInt(elements[i]);if ((l < 0L) || (l > 255L))return null;bytes[i] = (byte) (int) (l & 0xFF);}l = Integer.parseInt(elements[2]);if ((l < 0L) || (l > 65535L))return null;bytes[2] = (byte) (int) (l >> 8 & 0xFF);bytes[3] = (byte) (int) (l & 0xFF);break;case 4:for (i = 0; i < 4; ++i) {l = Integer.parseInt(elements[i]);if ((l < 0L) || (l > 255L))return null;bytes[i] = (byte) (int) (l & 0xFF);}break;default:return null;}} catch (NumberFormatException e) {System.out.println("数字格式化异常"+e);return null;}return bytes;}public static String getLocalIP() {String ip = "";if (System.getProperty("os.name").toLowerCase().startsWith("windows")) {InetAddress addr;try {addr = InetAddress.getLocalHost();ip = addr.getHostAddress();} catch (UnknownHostException e) {System.out.println("获取失败"+e);}return ip;} else {try {Enumeration<?> e1 = (Enumeration<?>) NetworkInterface.getNetworkInterfaces();while (e1.hasMoreElements()) {NetworkInterface ni = (NetworkInterface) e1.nextElement();if (!ni.getName().equals("eth0")) {continue;} else {Enumeration<?> e2 = ni.getInetAddresses();while (e2.hasMoreElements()) {InetAddress ia = (InetAddress) e2.nextElement();if (ia instanceof Inet6Address)continue;ip = ia.getHostAddress();return ip;}break;}}} catch (SocketException e) {System.out.println("获取失败"+e);}}return "";}
}

站点图:

总结

如果有人想窃取你的数据,如上配置之后,就可以用过滤器过滤掉高频率访问的ip了。但是人外有人天外有天,如果有人拿动态ip的话,那我们又该如何防范呢?

springboot 拦截高频率访问相关推荐

  1. 阿里面试题SpringBoot,出现频率较高的技术点汇总

    阿里面试题SpringBoot,出现频率较高的技术点汇总 1.什么是 Spring Boot? Spring Boot 是 Spring 开源组织下的子项目,是 Spring 组件一站式解决方案,主要 ...

  2. springboot拦截器 跳过_springboot创建拦截器过程图解

    springboot创建拦截器过程图解 这篇文章主要介绍了springboot创建拦截器过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一. ...

  3. 【SpringBoot】SpringBoot拦截器实战和 Servlet3.0自定义Filter、Listener

    =================6.SpringBoot拦截器实战和 Servlet3.0自定义Filter.Listener ============ 1.深入SpringBoot2.x过滤器Fi ...

  4. SpringBoot拦截器与过滤器

    一.拦截器与过滤器 在讲Spring boot之前,我们先了解一下过滤器和拦截器.这两者在功能方面很类似,但是在具体技术实现方面,差距还是比较大的.在分析两者的区别之前,我们先理解一下AOP的概念,A ...

  5. Springboot拦截器实现IP黑名单

    Springboot拦截器实现IP黑名单 一·业务场景和需要实现的功能 以redis作为IP存储地址实现.业务场景:针对秒杀活动或者常规电商业务场景等,防止恶意脚本不停的刷接口.实现功能:写一个拦截器 ...

  6. 高频率Vue面试题总结,vue面试就靠它!

    前言: 本文整理了一些高频率出现的 Vue 相关面试题. 大家可以先不看答案自测一下自己知道多少哈. 如果对答案有不一样见解或有更好的理解描述或更加详细的朋友欢迎评论区指出补充说明,谢谢~ 喜欢本文或 ...

  7. SpringBoot 拦截器和AOP自定义注解进行数据拦截实例

    声明:本文纯属个人随手笔记,如果对您有参考价值我十分开心,如果有存在错误,或者有更好的解决办法也麻烦您留言告诉我,大家共同成长,切勿恶言相. 欢迎加入资源共享QQ群:275343679,一起发现知识. ...

  8. 服务器设置虚拟内存有什么好处,高频率内存有哪些优势?虚拟内存是什么

    为增进大家对内存的认识,本文将为大家介绍高频率内存的优势.此外,小编还将对虚拟内存加以探讨. 我们每天都在同内存打交道,但大家对内存真的了解吗?上篇文章中,我们对服务器内存以及服务器内存技术有所介绍, ...

  9. springboot拦截器无法注入redisTemplate

    在工作中我们经常需要做登录拦截验证或者其他拦截认证功能,基于springboot项目下我们很容易想到结合redis做的分布式拦截,把用户登录或者需要验证的信息放到redis里面.但是在写拦截器的时候发 ...

  10. [SpringBoot][15][SpringBoot处理高并发]

    第 15 章 SpringBoot处理高并发 在企业实际应用中,会遇到很多高并发场景,最典型的例子就是双十一的抢购.这时候,如果仅仅按照之前简单的方式进行处理,不仅性能无法保证,而且有可能导致数据库某 ...

最新文章

  1. 随机抽样java_Reservoir Sampling 蓄水池抽样算法,经典抽样
  2. PHP通过header实现文本文件的下载
  3. DELPHI加密字串(异或运算加密)
  4. wp cron.php,wordpress定时任务(wp-cron.php)造成主机CPU比较高的解决办法
  5. 链表的分解(C++)
  6. 大数据之-Hadoop3.x_MapReduce_编程规范---大数据之hadoop3.x工作笔记0086
  7. centos 添加路由命令_详解CentOS 6.4 添加永久静态路由所有方法汇总
  8. 【好文翻译】10个免费的压力测试工具(Web)
  9. Spring事务原理分析(二)--@Transactional事务属性的解析
  10. CMD启动MySQL常用命令
  11. 专访爱情公寓CEO张家铭:中国SNS网站格局已定
  12. Excel文件减肥修复终极办法----解决Excel文件打开慢的问题
  13. CF417D--- Cunning Gena(序列+像缩进dp)
  14. 普罗米修斯(Prometheus)安装配置部署
  15. AI崛起,阿里的科技孵化力|甲子光年
  16. SQL语句group by 的求和sum
  17. html5 Doctor——教你规范使用html5标签
  18. 行测-图形推理-5-一笔画类
  19. 实现永久关闭445服务
  20. 风筝轮评测 风筝选购指南

热门文章

  1. php上传图片用年月日命名,thinkphp5中上传文件自定义命名规则
  2. 专家分析美金融危机对中国影响:充分估计其严重性
  3. php 项目迁移注意事项,网站数据迁移规范及注意事项
  4. 普通Java工程师 VS 优秀架构师
  5. 鸿蒙空间最高级,地球历史鸿蒙时代
  6. 专车数据层「架构进化」往事
  7. 【Python】Pillow 库入门
  8. HTML CSS 从一无所知到略知一二
  9. H5 - iOS和安卓时间显示不一致(显示NAN)
  10. 计算机组装过程中,电脑组装过程中的那些细节和难点