简单 DDos 防御程序

分三个部分
第一:ACLChecker类,负责统计及定时排除对象。
第二:ACLCheckFilter 每个类都会经过这个类。
第三:配置 web.xml的filter。
郑重声明:本程序还没通过大并发量的测试,等我有空做个benchmark后共享,仅供学习用,不要用于生产程序上。
package com.jongsuny.util;

import java.io.Serializable;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

/*
* @(#)ACLChecker.java $version 2012-11-18
*
* Copyright 2012- jongsuny. All rights Reserved.
* @Email:jongsuny@163.com
* @Messenser:jinjinzhe@hotmail.com
* Blog:http://hi.baidu.com/jjpx
*/

/**
*
* @author jongsuny
*/
public final class ACLCheckerNew {
private static String WHITE_LIST;
private static char[] WHITE_LIST_CHAR;
private static ConcurrentHashMap<String, ACLEntry> map = new ConcurrentHashMap<String, ACLEntry>(
1000, 0.75f, 300);
// private static final int THRESHOLD = 2000;
private static final int THRESHOLD = 500;
// private static final int CLEAN_INTERVAl = 60 * 1000 * 10;

private static final int CLEAN_INTERVAl = 10000;

public ACLCheckerNew(String whiteList) {
// WHITE_LIST = whiteList == null ? “” : whiteList;
WHITE_LIST = whiteList;
if (WHITE_LIST != null)
WHITE_LIST_CHAR = WHITE_LIST.toCharArray();
Thread thread = new Thread(new ExpiredEntryCleaner());
thread.start();
}

/***
* check if this key can access.
*
* @param key
* @return
*/
public boolean aclCheck(String key) {
if (key == null || “”.equals(key))
return false;
if (WHITE_LIST != null && checkWhiteList(key))
return true;
boolean acl = false;
ACLEntry entry = map.get(key);
if (entry == null) {
entry = new ACLEntry(System.currentTimeMillis());
map.put(key, entry);
} else {
acl = entry.updateACL();
if(acl)
System.out.println(“check for ” + key + “,result = ” + acl + “,” + entry.toString());
}
// System.out.println(entry.toString());
return acl;
}

/**
* return current map size.
*
* @return
*/
public int size() {
return map.size();
}

/**
* 获得字符串的next函数值
*
* @param t
* 字符串
* @return next函数值
*/
public static int[] next(char[] t) {
int[] next = new int[t.length];
next[0] = -1;
int i = 0;
int j = -1;
while (i < t.length – 1) {
if (j == -1 || t[i] == t[j]) {
i++;
j++;
if (t[i] != t[j]) {
next[i] = j;
} else {
next[i] = next[j];
}
} else {
j = next[j];
}
}
return next;
}

/**
* KMP check
*
* @return true if found.otherwise false
*/
public static boolean checkWhiteList(String key) {
char[] t = key.toCharArray();
int[] next = next(t);
int i = 0;
int j = 0;
while (i <= WHITE_LIST_CHAR.length – 1 && j <= t.length – 1) {
if (j == -1 || WHITE_LIST_CHAR[i] == t[j]) {
i++;
j++;
} else {
j = next[j];
}
}
if (j < t.length) {
return false;
} else
return true;
}

/***
*
* @author jongsuny
*/
final class ExpiredEntryCleaner implements Runnable {
public ExpiredEntryCleaner() {
}

/**
* clean expired entry.
*
* @return
*/
public int clean() {
int size = 0;
Set<Entry<String, ACLEntry>> entrySet = map.entrySet();
Iterator<Entry<String, ACLEntry>> it = entrySet.iterator();
while (it.hasNext()) {
Entry<String, ACLEntry> entry = it.next();
if (entry.getValue().expired()) {
System.err.println(“removing:” + entry.getKey() + “,count:”
+ entry.getValue().getVisitCount());
map.remove(entry.getKey());
size++;
}
}
return size;
}

/**
*
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
while (true) {
int size = size();
if (size > THRESHOLD) {
// clean
int cleanCount = clean();
System.err
.println(“cleanner cleaned count = ” + cleanCount+”,size = “+size);
}
try {
Thread.sleep(CLEAN_INTERVAl);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

/***
*
* @author jongsuny
*/
class ACLEntry extends ReentrantLock implements Serializable {
/**
*
*/
private static final long serialVersionUID = -4866168885805864706L;
private static final long runMode = 5000;//

private static final long resetSpan = runMode << 1;// private static final int countSpan = 1000; private static final int accessDenyValve = 25;// private static final int PENALTYTIME = 5000;// private boolean denied; private int visitCount; private int visitSpanCount; private long firstVisitTime; private long lastVisitTime; // 16 16 10 2 10 10 // /** * @param startTime * @param accessCount */ public ACLEntry(long nowMilsec) { super(); lock(); try { init(nowMilsec); } finally { unlock(); } } /** * @return the denied */ public boolean isDenied() { return denied; } /** * @param denied * the denied to set */ public void setDenied(boolean denied) { this.denied = denied; } /** * @return the visitCount */ public int getVisitCount() { return visitCount; } /** * @param visitCount * the visitCount to set */ public void setVisitCount(int visitCount) { this.visitCount = visitCount; } /** * @return the visitSpanCount */ public int getVisitSpanCount() { return visitSpanCount; } /** * @param visitSpanCount * the visitSpanCount to set */ public void setVisitSpanCount(int visitSpanCount) { this.visitSpanCount = visitSpanCount; } /** * @return the firstVisitTime */ public long getFirstVisitTime() { return firstVisitTime; } /** * @param firstVisitTime * the firstVisitTime to set */ public void setFirstVisitTime(long firstVisitTime) { this.firstVisitTime = firstVisitTime; } /** * @return the lastVisitTime */ public long getLastVisitTime() { return lastVisitTime; } /** * @param lastVisitTime * the lastVisitTime to set */ public void setLastVisitTime(long lastVisitTime) { this.lastVisitTime = lastVisitTime; } public String toString() { String res = “["; res += "denied:" + denied; res += ",visit:" + visitCount; res += ",visitSpan:" + visitSpanCount; res += ",first:" + firstVisitTime; res += ",last:" + lastVisitTime; res += "]“; return res; } /** * Gets the current value. * * @return the current value */ public final long get() { return firstVisitTime; } /** * Sets to the given value. * * @param newValue * the new value */ public final void set(long newValue) { lastVisitTime = newValue; } /*** * @param milSec * @return */ public boolean init(long milSec) { firstVisitTime = milSec; lastVisitTime = milSec; visitCount = 1; visitSpanCount = 1; denied = false; return false; } /*** * @param milSec * @return */ public boolean reset(long milSec) { visitCount = accessDenyValve / 2; visitSpanCount = 1; firstVisitTime = milSec; lastVisitTime = milSec; denied = false; return true; } /** * @param nvalue */ public void setValue(long nvalue) { firstVisitTime = nvalue; } /*** * @return */ public boolean expired() { long current = System.currentTimeMillis(); return (current – firstVisitTime > runMode);
}

/***
*
* @return
*/

public boolean denied() {
if (lastVisitTime – firstVisitTime > PENALTYTIME) {
reset(lastVisitTime);
return false;
}
return true;
}

/***
*
* @param firstAccessTime
* @param totalCount
* @return
*/
public boolean shiftCount(long firstAccessTime, long totalCount) {
return true;
}

/**
* update acl entry.
*
* @return
*/
public boolean updateACL() {
if (tryLock()) {
try {
// System.out.println(toString());
lastVisitTime = System.currentTimeMillis();
if (isDenied()) {
// 이미 acl에 걸린 사용자라면
return denied();
} else {
visitSpanCount++;
visitCount++;
if ((lastVisitTime – firstVisitTime) > resetSpan) {
init(lastVisitTime);
return false;
} else if ((lastVisitTime – firstVisitTime) > runMode) {
do {
visitCount -= visitSpanCount;
visitSpanCount = visitSpanCount >> 1;
if (visitSpanCount < 1) {
visitSpanCount = 1;
}
if (visitCount < 1) { firstVisitTime += countSpan; visitCount = 1; break; } firstVisitTime += countSpan; } while ((lastVisitTime – firstVisitTime) > runMode);
}
if (visitCount > accessDenyValve) {
denied = true;
}
return denied;
}
} finally {
// System.out.println(toString());
unlock();
}
} else {
return false;
}

}
}

}

第二步:ACLCheckFilter

/*
* @(#)ACLCheckFilter.java $version 2012-11-19
*
* Copyright 2012- jongsuny. All rights Reserved.
* Blog:http://kimnote.com
*/

package com.jongsuny.util;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

import com.jongsuny.util.ACLCheckerNew;

/**
* @author jongsuny
*/
public class ACLCheckFilter implements Filter {
private String whiteList;
private static ACLCheckerNew checker;

public String getWhiteList() {
return whiteList;
}

public void setWhiteList(String whiteList) {
this.whiteList = whiteList;
}

/**
* @param filterConfig
* @throws ServletException
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String white = getWhiteList();
checker = new ACLCheckerNew(white);
}

/**
* @param request
* @param response
* @param chain
* @throws IOException
* @throws ServletException
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String key = request.getRemoteAddr();
boolean result = checker.aclCheck(key);
// System.out.println(“check for ” + key + “,result = ” + result + “,time:”+System.currentTimeMillis());
if (result) {
HttpServletResponse res = (HttpServletResponse)response;
res.setStatus(403);
} else {
chain.doFilter(request, response);
}

}

/**
*
* @see javax.servlet.Filter#destroy()
*/
@Override
public void destroy() {
}

}
第三步:配置web.xml <filter>
<filter-name>accessFilter</filter-name>
<filter-class>com.jongsuny.util.ACLCheckFilter</filter-class>
<init-param>
<param-name>whiteList</param-name>
<param-value>127.0.0.1</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>accessFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>