Java编写web站点IP防护软核心,全内存操作 ,提供配置化(自己实现的 供大家参考) 博客文章
发布时间:2020-04-29 17:25:00 作者:本站编辑 来源:本站原创 浏览次数:
www.javainfo.com.cn 上干货 欢迎收藏
如有疑问 请留言 欢迎提供建议
基于Java编程的防护 可能速度达不到底层代码的速度,只是一个简单的编码实现 供大家鉴赏
项目框架及类分布 模拟页面分布
开始讲解各个文件的功能:
ChangLiang.java 常量设置 (读取ipcore.properties文件里的配置)
ipcore.properties ip计数器的核心属性配置, 字段说明在 ChangLiang.java文件里有详细说明
urlType=*.do
accessCount=10
hour=1
safeIpCheckNum=5
ipCount_minCount=15
ipBlack_minCount=20
ipCheck_minCount=25
public class ChangLiang { public static void main(String[] args) { ChangLiang a = new ChangLiang(); System.out.println(a); } /** * 标记防护的URL类型 *。jspx */ public static String urlType; /** * 访问次数 * <br/>单位时间内访问次数 达到这个值 当前的IP会被加入黑名单 */ public static Integer accessCount; /** * 秒 task执行任务频率 */ public static Integer ipCount_minCount; public static Integer ipBlack_minCount; public static Integer ipCheck_minCount; /** * IP封禁小时数,及IP存储在黑名单里的时长,若超过hour小时则 自动解禁 */ public static Integer hour; /** * IP安全检查次数 ,若IP检查三次 后 访问量正常 则IPcount 自动清理改IP */ public static Integer safeIpCheckNum; public static final SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss"); /** * 获取当前时间点 * @return */ public static String getNowtime(){ return sdf.format(new Date()); } static{ Properties pro = new Properties(); FileInputStream in; try { String path = ChangLiang.class.getResource("/").getFile()+"com/fanghu/core/ipcore.properties"; in = new FileInputStream(path); pro.load(in); in.close(); urlType = pro.getProperty("urlType"); accessCount = Integer.valueOf(pro.getProperty("accessCount")); ipCount_minCount = Integer.valueOf(pro.getProperty("ipCount_minCount")); ipBlack_minCount = Integer.valueOf(pro.getProperty("ipBlack_minCount")); ipCheck_minCount = Integer.valueOf(pro.getProperty("ipCheck_minCount")); hour = Integer.valueOf(pro.getProperty("hour")); safeIpCheckNum = Integer.valueOf(pro.getProperty("safeIpCheckNum")); System.out.println("urlType="+urlType+";accessCount="+accessCount+";ipCount_minCount="+ipCount_minCount+ ";ipBlack_minCount="+ipBlack_minCount+";ipCheck_minCount="+ipCheck_minCount+ ";hour="+hour+";safeIpCheckNum="+safeIpCheckNum ); } catch (Exception e) { e.printStackTrace(); } } }
客户端IP抓取 IPcatch.java:
/** * web客户 ip抓取 ,未特殊验证是否满足设计要求,一般直接访问 代理访问 都能拦截 * @author 此方法来源网络,若有侵权请留言 * */ public class IPcatch { /** * 获取用户真实IP地址,不使用request.getRemoteAddr()的原因是有可能用户使用了代理软件方式避免真实IP地址, * 可是,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP值 * * @return ip */ public String getIpAddr(HttpServletRequest request) { String ip = request.getHeader("x-forwarded-for"); // System.out.println("x-forwarded-for ip: " + ip); if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) { // 多次反向代理后会有多个ip值,第一个ip才是真实ip if( ip.indexOf(",")!=-1 ){ ip = ip.split(",")[0]; } } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); // System.out.println("Proxy-Client-IP ip: " + ip); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); //System.out.println("WL-Proxy-Client-IP ip: " + ip); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); //System.out.println("HTTP_CLIENT_IP ip: " + ip); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); // System.out.println("HTTP_X_FORWARDED_FOR ip: " + ip); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("X-Real-IP"); //System.out.println("X-Real-IP ip: " + ip); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); // System.out.println("getRemoteAddr ip: " + ip); } // System.out.println("获取客户端ip: " + ip); return ip; } }
ip计数器 对于某类访问的客户IP进行技术统计,并读取白名单数据
ipwhite.txt ip白名单 用户避免一些具有网IP或必要的IP被拦截
127.0.0.1
127.0.0.3
0:0:0:0:0:0:0:1
/** * IP访问量计数核心 对一类URI进行处理 * @author WJ */ public class IPcount { /** * 存储IP白名单 IP , 1 */ public static Map<String,Integer> ipWhiteMap = new HashMap<String, Integer>(); static{ String ip = ""; String path = ChangLiang.class.getResource("/").getFile()+"com/fanghu/core/ipwhite.txt"; FileReader f; try { f = new FileReader(path); BufferedReader br = new BufferedReader(f); while((ip = br.readLine()) != null){ ipWhiteMap.put(ip, 1); } System.out.println("初始化IP白名单OK "+ipWhiteMap.size()); } catch (Exception e) { e.printStackTrace(); } } public IPcount() { super(); } /** * 存储IP计数临时数据 (内存中维护) IP count */ public static Map<String,Integer> ipCountMap = new HashMap<String, Integer>(); /** * 存储IP黑名单数据 IP , 1 */ public static Map<String,Long> ipBlackMap = new HashMap<String, Long>(); /** * 0 放行; 1 阻止; * <br/>黑名单 不会再记录数目 , 白名单不会记录数目 直接放行 * <br/>不属于上面两种的, 计数处理 * @param ip * @return */ public static int process(String ip){ if(ipWhiteMap.containsKey(ip)) return 0; if(ipBlackMap.containsKey(ip)) return 1; if(ipCountMap.containsKey(ip)){ ipCountMap.put(ip, Integer.valueOf(ipCountMap.get(ip) + 1)); }else{ ipCountMap.put(ip, 1); } pringIpcount(ipCountMap); return 0; } static void pringIpcount(Map<String,Integer> map){ Iterator<String> it = map.keySet().iterator(); String ip = null; System.out.println("***************************start**************************************************"); while(it.hasNext()){ ip = it.next(); System.out.println("ipCoungMap detail --------------------- "+ip +" count: " + map.get(ip)); } System.out.println("****************************end*************************************************"); } }
IP动态维护任务 ipCheckingTask.java(核心)
/** * IP检查任务,标记哪些IP 应该移入黑名单,这样这个IP池 会自动维护,不用人工干预 * @author Administrator */ public class IpCheckingTask { public static void IpCheckingMain(){ try { System.out.println("开始启用IP防御核心 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。"); ipCountCheck(); //启用IP计数器过滤线程 ipBlackCheckTask(); //启用黑名单超时释放线程 ipCountClearTask(); //启用safeIP清理线程 System.out.println("IP防御核心 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。启动完成。。"); } catch (Exception e) { e.printStackTrace(); } } /** * IP校验计时器 IP 校验次数 */ static Map<String,Integer> checkIpNums = new HashMap<String,Integer>(); //============================================================ /** * 任务一 单位时间内 访问次数达标的IP 移入 IPBLACK * @throws Exception */ public static void ipCountCheck() throws Exception{ Runnable runnable = new Runnable() { public void run() { int count = 0; String ip = null; List<String> toBlackIp = new ArrayList<String>(); //System.out.println("ipCountCheck "+ChangLiang.getNowtime()); Iterator<String> ipIt = IPcount.ipCountMap.keySet().iterator(); while(ipIt.hasNext()){ ip = ipIt.next(); count = IPcount.ipCountMap.get(ip); System.out.println("ipchecking: count="+count +" changLiangaccesscount="+ChangLiang.accessCount); if(count >= ChangLiang.accessCount){ toBlackIp.add(ip); System.out.println("ipCountMap toblack ==================================" + ip); } //将校验数据存入历史数据内,用于校验是否是正常的IP访问 else{ if(checkIpNums.containsKey(ip)){ Integer ipSaomiao = checkIpNums.get(ip) + 1; System.out.println("checkIpNums ==add=====" + ip +" saomiaoNum = "+ipSaomiao); checkIpNums.put(ip, ipSaomiao); }else{ checkIpNums.put(ip, 1); System.out.println("checkIpNums ===init====" + ip +" saomiaoNum = "+1); } } } //System.out.println("校验完毕,开始处理数据,同时清理safeIP计数缓存"); if(toBlackIp.size() > 0){ Date now = new Date(); for(String t : toBlackIp){ IPcount.ipCountMap.remove(t); checkIpNums.remove(t); IPcount.ipBlackMap.put(t, now.getTime()); System.out.println("ipCountMap[ipBlackMap checkIpNums] remove[add remove] " + t +" timeLong = " + now.getTime()); } //System.out.println("IPcount 清理了 IP " + toBlackIp.size() +"个"); toBlackIp = null; ipIt = null; now = null; ip = null; }else{ System.out.println("ipCountCheck 无须处理 。。。。 IPCOUNT TASK "); } } }; ScheduledExecutorService service = Executors .newSingleThreadScheduledExecutor(); // 第二个参数为首次执行的延时时间,第三个参数为定时执行的间隔时间 单位时间为 S service.scheduleAtFixedRate(runnable, 5, ChangLiang.ipCount_minCount, TimeUnit.SECONDS); } //======================================================== //============================================================ /** * 任务2 黑名单任务 封禁时间达标的IP 自动释放 * @throws Exception */ public static void ipBlackCheckTask() throws Exception{ Runnable runnable = new Runnable() { public void run() { //System.out.println("ipBlackCheckTask "+ChangLiang.getNowtime()); Iterator<String> ipBlack = IPcount.ipBlackMap.keySet().iterator(); String ip=null; Date now = new Date(); List<String> toDel = new ArrayList<String>(); while(ipBlack.hasNext()){ ip = ipBlack.next(); long toBlackTime = IPcount.ipBlackMap.get(ip); //测试环境 封存时间按照 S 来计算 //if(( now.getTime() - ChangLiang.hour * 60 * 1000 ) > toBlackTime){ if(( now.getTime() - ChangLiang.hour * 3600 * 1000 ) > toBlackTime){ System.out.println("封存时间已经超过了约定的时间,黑名单释放"+ip +" nowGetTime = "+now.getTime() +" fff="+ChangLiang.hour * 60 +" toBlackTime="+toBlackTime); toDel.add(ip); } } //System.out.println("黑名单任务校验完毕,开始处理数据"); if(toDel.size() > 0){ for(String t : toDel){ IPcount.ipBlackMap.remove(t); System.out.println("ipBlackMap 清理了 IP " +t); } toDel = null; now = null; ipBlack = null; }else{ System.out.println("ipBlackCheckTask ------------ 无须处理 。。。。 TASK "); } } }; ScheduledExecutorService service = Executors .newSingleThreadScheduledExecutor(); // 第二个参数为首次执行的延时时间,第三个参数为定时执行的间隔时间 单位时间为 S service.scheduleAtFixedRate(runnable, 5, ChangLiang.ipBlack_minCount, TimeUnit.SECONDS); } //======================================================== //============================================================ /** * 为了保持效率 清除正常访问IP<br/> * 任务3 若满足释放条件的IP 清理出IPcount (及可能是正常的访问 非经常访问的IP) * @throws Exception */ public static void ipCountClearTask() throws Exception{ Runnable runnable = new Runnable() { public void run() { System.out.println("ipCountClearTask "+ChangLiang.getNowtime()); Iterator<String> ipIt = checkIpNums.keySet().iterator(); String ip = null; List<String> safeIp = new ArrayList<String>(); while(ipIt.hasNext()){ ip = ipIt.next(); System.out.println("safeIpcheck IP= "+ip +" 安全校验次数 "+checkIpNums.get(ip) +" ; 安全校验标准次数 "+ ChangLiang.safeIpCheckNum); if(checkIpNums.get(ip) >= ChangLiang.safeIpCheckNum){ safeIp.add(ip); } } //System.out.println("safeIP 数据处理完成,开始清理 "); if(safeIp.size() > 0){ for(String si : safeIp){ checkIpNums.remove(si); IPcount.ipCountMap.remove(si); System.out.println("安全IP释放 IPcount[checkIpNums] remove[remove]= "+si); } // System.out.println("ipCount safeIp清理完成 " + safeIp.size()); safeIp = null; ip = null; ipIt = null; }else{ System.out.println("safeIp 无须清理 ,没有满足条件的IP "); } IPcount.pringIpcount(IPcount.ipCountMap); } }; ScheduledExecutorService service = Executors .newSingleThreadScheduledExecutor(); // 第二个参数为首次执行的延时时间,第三个参数为定时执行的间隔时间 单位时间为 S service.scheduleAtFixedRate(runnable, 10, ChangLiang.ipCheck_minCount, TimeUnit.SECONDS); } }
IPcheckFilter.java 核心部署 依赖web的过滤器FILTER,上代码 哪些操作频繁需要防护可以在过滤器上调整
@WebFilter("/*") public class IpCheckFilter implements Filter { private IPcatch ipCatch = null; /** * Default constructor. */ public IpCheckFilter() { // TODO Auto-generated constructor stub } /** * @see Filter#destroy() */ public void destroy() { // TODO Auto-generated method stub } /** * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain) */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub // place your code here //特殊请求 特殊处理,如提示访问频繁的界面 HttpServletRequest req = (HttpServletRequest)request; String url = req.getRequestURL().toString(); System.out.println("url: ------------- = "+url); if(url.indexOf("res403") > 0){ chain.doFilter(request, response); return; } //截取访问客户端的IP String webUserIp = ipCatch.getIpAddr(req); System.out.println("filterWebUserIp=" + webUserIp); //IP通过防护核心的IP计数器 记录一下 int rsInt = IPcount.process(webUserIp); if(rsInt == 0){ //防护核心认为 可以通行 chain.doFilter(request, response); }else{ //未通过防护核心 HttpServletResponse res = (HttpServletResponse) response; res.setStatus(403); request.getRequestDispatcher("/res403.jsp").forward(request, response); } } /** * @see Filter#init(FilterConfig) */ public void init(FilterConfig fConfig) throws ServletException { // TODO Auto-generated method stub //启动IP防御核心 IpCheckingTask.IpCheckingMain(); //启动IP抓取功能 ipCatch = new IPcatch(); System.out.println("filter OK "); System.out.println("IPcatch process OK "); } }
全内存操作 速度还可以
测试打印如下,可以正常提供拦截服务
初始化IP白名单OK 3 url: ------------- = http://192.168.2.222/ filterWebUserIp=192.168.2.222 ipCoungMap detail --------------------- 192.168.2.222 count: 1 ipchecking: count=1 changLiangaccesscount=10 checkIpNums ===init====192.168.2.222 saomiaoNum = 1 ipCountCheck 无须处理 。。。。 IPCOUNT TASK ipBlackCheckTask ------------ 无须处理 。。。。 TASK url: ------------- = http://192.168.2.222/ filterWebUserIp=192.168.2.222 ipCoungMap detail --------------------- 192.168.2.222 count: 2 url: ------------- = http://192.168.2.222/ filterWebUserIp=192.168.2.222 ipCoungMap detail --------------------- 192.168.2.222 count: 3 url: ------------- = http://192.168.2.222/ filterWebUserIp=192.168.2.222 ipCoungMap detail --------------------- 192.168.2.222 count: 4 url: ------------- = http://192.168.2.222/ filterWebUserIp=192.168.2.222 ipCoungMap detail --------------------- 192.168.2.222 count: 5 url: ------------- = http://192.168.2.222/ filterWebUserIp=192.168.2.222 ipCoungMap detail --------------------- 192.168.2.222 count: 6 url: ------------- = http://192.168.2.222/ filterWebUserIp=192.168.2.222 ipCoungMap detail --------------------- 192.168.2.222 count: 7 ipCountClearTask 2020-04-29 14:27:34 safeIpcheck IP= 192.168.2.222 安全校验次数 1 ; 安全校验标准次数 5 safeIp 无须清理 ,没有满足条件的IP url: ------------- = http://192.168.2.222/ filterWebUserIp=192.168.2.222 ipCoungMap detail --------------------- 192.168.2.222 count: 8 url: ------------- = http://192.168.2.222/ filterWebUserIp=192.168.2.222 ipCoungMap detail --------------------- 192.168.2.222 count: 9 url: ------------- = http://192.168.2.222/ filterWebUserIp=192.168.2.222 ipCoungMap detail --------------------- 192.168.2.222 count: 10 url: ------------- = http://192.168.2.222/ filterWebUserIp=192.168.2.222 ipCoungMap detail --------------------- 192.168.2.222 count: 11 url: ------------- = http://192.168.2.222/ filterWebUserIp=192.168.2.222 ipCoungMap detail --------------------- 192.168.2.222 count: 12 url: ------------- = http://192.168.2.222/ filterWebUserIp=192.168.2.222 ipCoungMap detail --------------------- 192.168.2.222 count: 13 url: ------------- = http://192.168.2.222/ filterWebUserIp=192.168.2.222 ipCoungMap detail --------------------- 192.168.2.222 count: 14 ipchecking: count=14 changLiangaccesscount=10 ipCountMap toblack ==================================192.168.2.222 ipCountMap[ipBlackMap checkIpNums] remove[add remove] 192.168.2.222 timeLong = 1588141664184 ipBlackCheckTask ------------ 无须处理 。。。。 TASK ipCountCheck 无须处理 。。。。 IPCOUNT TASK ipCountClearTask 2020-04-29 14:27:59 safeIp 无须清理 ,没有满足条件的IP ipBlackCheckTask ------------ 无须处理 。。。。 TASK ipCountCheck 无须处理 。。。。 IPCOUNT TASK ipCountClearTask 2020-04-29 14:28:24 safeIp 无须清理 ,没有满足条件的IP ipCountCheck 无须处理 。。。。 IPCOUNT TASK ipBlackCheckTask ------------ 无须处理 。。。。 TASK ipCountCheck 无须处理 。。。。 IPCOUNT TASK 封存时间已经超过了约定的时间,黑名单释放192.168.2.222 nowGetTime = 1588141729186 fff=60 toBlackTime=1588141664184 ipBlackMap 清理了 IP 192.168.2.222 ipCountClearTask 2020-04-29 14:28:49 safeIp 无须清理 ,没有满足条件的IP ipCountCheck 无须处理 。。。。 IPCOUNT TASK ipBlackCheckTask ------------ 无须处理 。。。。 TASK
如有疑问 请留言 欢迎提供建议
评论已有 0 条