舍友的攻击方法很简单,就是并发的产生非常非常多线程去请求网站首页。
针对这样的攻击就做了个IP过滤,把短时间内的产生大量访问的IP划入黑名单,然后拦截。
使用的是JFinal框架,所以就写了IpFiterHandler做拦截。
流程
获取访问IP
————判断是否在黑名单中(一个SET集合)
——————在黑名单则return;
——————不存在 记录IP
——判断该IP是否在访问过 或 在规定时间内访问过多次(访问过的IP放到MAP集合中
——判断IP的在规定时间内访问的次数是否超过最大限制 超过则ADD到黑名单中
public class IpFilterHandler extends Handler{
private static Logger log = Logger.getLogger(Handler.class);
@Override
public void handle(String target, HttpServletRequest request,
HttpServletResponse response, boolean[] isHandled) {
String ip = IpHelp.getIpAddr(request);
if(StrKit.isBlank(ip) || IpHelp.isBlackIp(ip)){
log.error("被拦截的黑名单Ip :" + ip);
isHandled[0] = true;
return ;
}
IpHelp.recordIp(ip);
nextHandler.handle(target, request, response, isHandled);
}
}
package com.anna.config.handler;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import com.jfinal.log.Logger;
public class IpHelp {
private static Logger log = Logger.getLogger(IpHelp.class);
private long expireTime;
private int accessNum = 0;
/**在这个时间段内访问次数超过限制则划入黑名单*/
private static long expireL = 60_000L;
private static int MaxAccess = 300;
/**记录访问过的IP*/
private static Map<String, IpHelp> ipAccessed = new HashMap<String, IpHelp>();
/**划入黑名单的IP*/
private static Set<String> blackIps = new HashSet<String>();
private IpHelp(){
this.expireTime = System.currentTimeMillis() + expireL;
}
/**
* 判断是否IP是否已经过期<br>
* 访问次数+1
* @return 过期返回true
*/
private boolean isExpore(){
accessNum ++;
return System.currentTimeMillis() > this.expireTime;
}
/**
* 记录Ip
* @param ip
*/
public static void recordIp(String ip){
IpHelp ipHelp = ipAccessed.get(ip);
if(ipHelp == null || ipHelp.isExpore()){
log.info("访问的Ip: " + ip);
ipAccessed.put(ip, new IpHelp());
}else if(ipHelp.getAccessNum()> MaxAccess){
log.error("加入黑名单Ip: " + ip);
blackIps.add(ip);
}
}
public static boolean isBlackIp(String ip){
return blackIps.contains(ip);
}
public static void clearIps(){
ipAccessed.clear();
blackIps.clear();
}
public static String getIpAddr(HttpServletRequest request) {
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("WL-Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
public int getAccessNum() {
return accessNum;
}
}