科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道Java Web中的入侵检测及简单实现

Java Web中的入侵检测及简单实现

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

Java Web中的入侵检测及简单实现

作者:dxaw 来源:赛迪网技术社区赛迪网 2007年11月24日

关键字: 入侵检测 Java Web

  • 评论
  • 分享微博
  • 分享邮件

在Java Web应用程中,特别是网站开发中,我们有时候需要为应用程序增加一个入侵检测程序来防止恶意刷新的功能,防止非法用户不断的往Web应用中重复发送数据。当然,入侵检测可以用很多方法实现,包括软件、硬件防火墙,入侵检测的策略也很多。在这里我们主要介绍的是Java Web应用程序中通过软件的方式实现简单的入侵检测及防御。 =43?vCeYv}  
d$=R;e"U  
  该方法的实现原理很简单,就是用户访问Web系统时记录每个用户的信息,然后进行对照,并根据设定的策略(比如:1秒钟刷新页面10次)判断用户是否属于恶意刷新。 R,z._1cM;  
YGOXps5}  
  我们的入侵检测程序应该放到所有Java Web程序的执行前,也即若发现用户是恶意刷新就不再继续执行Java Web中的其它部分内容,否则就会失去了意义。这就需要以插件的方式把入侵检测的程序置入Java Web应用中,使得每次用户访问Java Web,都先要到这个入侵检测程序中报一次到,符合规则才能放行。 "o"4{QxK>V  
)['rVR#Oa  
  Java Web应用大致分为两种,一种纯JSP(+Java Bean)方式,一种是基于框架(如Struts、EasyJWeb等)的。第一种方式的Java Web可以通过Java Servlet中的Filter接口实现,也即实现一个Filter接口,在其doFilter方法中插入入侵检测程序,然后再web.xml中作简单的配置即可。在基于框架的Web应用中,由于所有应用都有一个入口,因此可以把入侵检测的程序直接插入框架入口引擎中,使框架本身支持入侵检测功能。当然,也可以通过实现Filter接口来实现。 3iYhIK1HT,  
qc$/QM2d m  
  在EasyJWeb框架中,已经置入了简单入侵检测的程序,因此,这里我们以EasyJWeb框架为例,介绍具体的实现方法及源码,完整的代码可以在EasyJWeb源码中找到。 vG.Mduf4  
3PR $te  
  在基于EasyJWeb的Java Web应用中(如http://www.easyjf.com/bbs/),默认情况下你只要连续刷新页面次数过多,即会弹出如下的错误: 3*GfQ  
;/'sS+K(2  
  EasyJWeb框架友情提示!:-): PYtwE1\  
  您对页面的刷新太快,请等待60秒后再刷新页面! 75M@s]_s  
  详细请查询http://www.easyjf.com . c%PVF?03  
'n[u)7{(  
o<XX4?)`  
二、用户访问信息记录UserConnect.java类   F2SV X/}\  
6*SeL/ON  
  这个类是一个简单的Java Bean,主要代表用户的信息,包括用户名、IP、第一次访问时间、最后登录时间、登录次数、用户状态等。全部 ?8c@1&  
0+0pX'  
代码如下: |)~r[xRt  
=n$CR PQ  
package com.easyjf.web; it8] A  
Iasv nmW  
import java.util.Date; q5!7yON`k  
/** l Ir"  
* m=4qq`  
* ,(DUDy""/  
J_mgd*>  
Title:用户验证信息 ,C}LJVuy  
 y6xPE   
H8H-C_  
* Kf@B(+@tIh  
Description:记录用户登录信息,判断用户登录情况 B10\YO@|->  
cEwty%  
dixnn0z  
* 5*PS  a  
Copyright: Copyright (c) 2006 doBz 8Qt  
ELI$~?CM1  
9v-i=^SHR1  
* RdUfgxC:v  
Company: www.easyjf.com OT]w{tp6w  
Z@*sm  
/wD_MM;-  
* @author 蔡世友 [X:y  
* @version 1.0 ~Nt-jDe8O  
*/ JL@6Q;V2  
public class UserConnect { v8[-\h  
private String userName; #yRSR\  
private String ip; X,. h  
private Date firstFailureTime; ER;R\_#  
private Date lastLoginTime; ,DXARdh>+[  
private int failureTimes;//用户登录失败次数 mM@)2}B9  
private int status=0;//用户状态0表示正常,-1表示锁定 g:vrUikK  
public int getFailureTimes() { QDmKpMHA  
return failureTimes; Ogss9  
} Rl{],b^v  
public void setFailureTimes(int failureTimes) { Df%5;U  
this.failureTimes = failureTimes; k 93A  
} Wlo%QlZn  
public Date getFirstFailureTime() { Z%XVV*)Ml  
return firstFailureTime; So@?XoS;  
} - 8 O  
)hg_*0U  
public void setFirstFailureTime(Date firstFailureTime) { {gI2zhn]  
this.firstFailureTime = firstFailureTime; +--0/  
} UoU Dv.J  
cJtvF/  
public String getIp() { qyMoY, jW  
return ip; $' uZiH  
} S\qTZB{  
wdr$%cI1HT  
public void setIp(String ip) { h~r\s(Mj/i  
this.ip = ip; }/j&= E! 8  
} RN4p9'T  
}f $pkyT+c  
public Date getLastLoginTime() { I _5%;  
return lastLoginTime; (.Gx857cF  
} DY/3Kuv  
9(vr {?_  
public void setLastLoginTime(Date lastLoginTime) { 4#v6k-9  
this.lastLoginTime = lastLoginTime; !rn7 |hb  
} 1)TEI^ L]f  
 CXC"Ti  
public String getUserName() { G'*r q  
return userName; 1rll-  
} =~:Sa rj  
.k/6(9:-c  
public void setUserName(String userName) { /})Gb !\  
this.userName = userName; ^ (mO:n  
} ICBs{q}RN  
EBB9`SZK  
public int getStatus() { EE|j#_<Z}  
return status; 69hCs_NK  
} ?c$7^fTvV  
y$ <ut1S.  
public void setStatus(int status) { +ix9H?:d%  
this.status = status; UT SRVWAQZ  
} _\hhJ 5/  
N.NB3Axs/  
} L$vIw/{O  
三、监控线程UserConnectManage.java类 lun]4`  
1v{ ! gk  
  这是入侵检测的核心部分,主要实现具体的入侵检测、记录、判断用户信息、在线用户的刷新等功能,并提供其它应用程序使用本组件的调用接口。 'AJwwP.X  
{e ty.[  
package com.easyjf.web; f,;{']?&  
C.;|$Dwy'  
import java.util.Date; \:k$;vm  
import java.util.HashMap; S/XFUsK!hy  
import java.util.HashSet; Df9 ~ X  
import java.util.Iterator; -,{JHuF&  
import java.util.Map; w} j-E  
import java.util.Set; P5FK0W=E  
oKyz89  
import org.apache.log4j.Logger; VP:5C. Q&  
/** c_&U h=&C  
* Y{. 0  
* s#<hnZle.  
bx V5R-n  
Title:用户入侵检测信息 eL "W,jb  
&!xa9:%  
n W'L  
* Oa?j9BMn  
Description:用于判断用户刷新情况检查,默认为10秒钟之内连续连接10次为超时 2^&4uIN/)  
-z^,C5(C  
1p6N'P38  
* Tuw{ j   
Copyright: Copyright (c) 2006 %Bv3!0_"  
g f,:%R  
ta[g"BXv  
* :k(y9rYc  
Company: www.easyjf.com [.5=(3B,j  
Kd4i%J4[jQ  
|nb-  
* @author 蔡世友 (m>Q}$G  
* @version 1.0 e T!n6<!7  
*/ 8 ]{LqC  
public class UserConnectManage { )&,#7  
private static final Logger logger = (Logger) Logger.getLogger(UserConnectManage.class.getName()); I[xR .p  
private static int maxFailureTimes=10;//最大登录失败次数 `du:AE=  
private static long maxFailureInterval=10000;//毫秒,达到最大登录次数且在这个时间范围内 /z.a$(@4  
private static long waitInterval=60000;//失败后接受连接的等待时间,默认1分钟 '4</L&w  
private static int maxOnlineUser=200;//同时在线的最大数 e])mC8p  
private final static Map users=new HashMap();//使用ip+userName为key存放用户登录信息UserLoginAuth 0{&|E4  
private static Thread checkThread=null; ]bZ U/  
private static class CheckTimeOut implements Runnable{ V C"9  
private Thread parentThread; 1@&CEnQ  
public CheckTimeOut(Thread parentThread) pgh<DF;  
{ N.DnC0l  
this.parentThread=parentThread; vRf^J`?-  
synchronized(this){ #+ \||E/IY  
if(checkThread==null){ >CD'JUcm  
checkThread= new Thread(this); ix)S;|YTG  
//System.out.println("创建一个新线程!"); KobL=qdx  
checkThread.start(); 5[74m}  
} [uW,6c->%  
} = W6#2rS61  
} '#<,5nlI  
public void run() { 'rzZ0uHjxn  
while(true) %6N  
{ 8iCU|?bm  
if(parentThread.isAlive()){ 'W[Yes(P2  
try{ (zbV/ ^W V  
Thread.sleep(2000);  SZt\TF  
int i=0; Ll<Uu$;^  
if(users.size()>maxOnlineUser)//当达到最大用户数时清除 X]K xG:  
{  r p(+y(  
synchronized(users){//执行删除操作 [Zc/m`c  
Iterator it=users.keySet().iterator(); JOHZnay  
Set set=new HashSet(); xim3;a7:  
Date now=new Date(); =UhXdMFTC  
while(it.hasNext()) y[B/ ND6  
{ )8/{8Hs  
Object key=it.next(); gjL|8s]  
UserConnect user=(UserConnect)users.get(key); Kokl2`_A  
if(now.getTime()-user.getFirstFailureTime().getTime()>maxFailureInterval)//删除超时的用户 :quB2#6k  
{ |E<s2%K~  
set.add(key); 6bXoq.<  
logger.info("删除了一个超时的连接"+i); /Re,-K4h  
i++; a+.-M#[  
} z7[n1t!  
} Au*%yVJz  
if(i<5)//如果删除少于5个,则强行删除1/2在线记录,牺牲性能的情况下保证内存 cg9=`O*]X8  
{ z0I\3g0  
int num=maxOnlineUser/2; c1+g117t\  
it=users.keySet().iterator(); IU!n. LS  
while(it.hasNext() && i { qJg ^  
set.add(it.next()); CH 7C-) E  
logger.info("删除了一个多余的连接"+i); DMoj jM^  
i++; JD{TcneOf  
} vlFE%*9  
} H- /1)?  
users.keySet().removeAll(set); FwPO[}9G  
} YX BjNK  
} Bev:!%]R  
SRq|Mv_R  
} 5O tMn"  
catch(Exception e) oGg.~I,ht  
{ 6s1_'j93,S  
e.printStackTrace(); jCb=-fi  
} \SFTJ )&  
/8$ZO  
} ^wVG)=$$I  
else y" XPA~s  
{ {V;Xh`G?E  
break; wRvVZfWRJ  
} [CMY $~  
} @/7>A1'G  
logger.info("监视程序运行结束!"); v~;w+F==rf  
} T9o_b.6  
} Ox1?(E \r>  
//通过checkLoginValidate判断是否合法的登录连接,如果合法则继续,非法则执行 ~7@xI/|  
public static boolean checkLoginValidate(String ip,String userName)//只检查认证失败次数 osW%oe$  
{ ft=@R,B  
boolean ret=true; You+97ET  
Date now=new Date(); `-Sm 0~&H  
String key=ip+":"+userName; ,Q;: |P  
UserConnect auth=(UserConnect)users.get(key); h'  Td0C  
if(auth==null)//把用户当前的访问信息加入到users容器中 (w"(wxkl  
{ |mLx'/   
auth=new UserConnect(); xbX B/-  
auth.setIp(ip); {EpT`^Q  
auth.setUserName(userName); V U  
auth.setFailureTimes(0); ,R-!#z}R  
auth.setFirstFailureTime(now); oJj\@m2;  
users.put(key,auth); 3 E) ?:i\  
if(checkThread==null)new CheckTimeOut(Thread.currentThread()); WVQWlb-.  
} vB,MnY  
else r!u.O9  
{ 0|G;N]u  
if(auth.getFailureTimes()>maxFailureTimes) bW 0QBNP  
{ "ZX|m%'  
//如果在限定的时间间隔内,则返回拒绝用户连接的信息 qKoL%pW;  
if((now.getTime()-auth.getFirstFailureTime().getTime()) { *:x^FQ2e  
ret=false; ykQR4o1z  
auth.setStatus(-1); ;L6yd= r  
} yHNx-f'  
else if(auth.getStatus()==-1 && (now.getTime()-auth.getFirstFailureTime().getTime()<(maxFailureInterval+waitInterval)))//重置计数器  t;5 _is  
{ ]gsm#M%$I  
ret=false; VNcd]_D  
} <y55G I3[  
else ydC 3L;qb  
{ m2>Y\#B8  
auth.setFailureTimes(0); & Sm5s  
auth.setFirstFailureTime(now); 6t  -p  
auth.setStatus(0); gQ/ ?Z^G  
} Fw9}x"c 7a  
nuRb O0'  
} Y{dazNXm&  
//登录次数加1 )F+ >buG  
auth.setFailureTimes(auth.getFailureTimes()+1); xB*_ w o  
} )J(x>ntZ  
//System.out.println(key+":"+auth.getFailureTimes()+":"+ret+":"+(now.getTime()-auth.getFirstFailureTime().getTime())); Hn1z Au  
return ret; ,}/AEo(@\  
} X(,:o4m3  
gw HWmrq  
public static void reset(String ip,String userName)//重置用户信息 JOxC pa~  
{ 2:7yq4.  
Date now=new Date(); xZRgJqK  
String key=ip+":"+userName; W zPL&d  
UserConnect auth=(UserConnect)users.get(key); H" ?_@d_  
if(auth==null)//把用户当前的访问信息加入到users容器中 j8 b{5^#9  
{ J^{Xw](P  
auth=new UserConnect(); =0l 1.U  
auth.setIp(ip); bs@*"   
auth.setUserName(userName); /g^`-7;NF  
auth.setFailureTimes(0); Z IY"+  
auth.setFirstFailureTime(now); & YUOSL  
users.put(key,auth); %dLk p&67  
} ak`~WHOVe  
else P4(h2pvh  
{ Bs N y8f|  
auth.setFailureTimes(0); $A54PD0  
auth.setFirstFailureTime(now); ?jB Wtx%\  
} 4r+kO^m5  
} IOdX <1l  
public static void remove(String ip,String userName)//删除用户在容器中的记录 )bZ.>v#M>  
{ r&pfry1fc~  
String key=ip+":"+userName; \Ow4ag0  
users.remove(key); xBcG0+  
} ,0&<fO?C  
public static void clear()//清空容器中内容 y;dc9 \.V  
{ hWN|"  
if(!users.isEmpty())users.clear(); KQaK )l)  
} `,<nT#j@  
public static long getMaxFailureInterval() { e !ml ;b%  
return maxFailureInterval; TxVO~x#h  
} 9 j43p  
hc;+i_@.l  
public static void setMaxFailureInterval(long maxFailureInterval) { lwLlwfxB#L  
UserConnectManage.maxFailureInterval = maxFailureInterval; )=2*YG-p  
} 9 <cP01+B  
FnY8Zn=  
public static int getMaxFailureTimes() { kxJDKP m  
return maxFailureTimes; z7Mhfhc  
} E/pzi/czF2  
ts]aw7u];  
public static void setMaxFailureTimes(int maxFailureTimes) { tP&YZ0e  
UserConnectManage.maxFailureTimes = maxFailureTimes; ec8hRcyi  
} |.;3%~rS!  
Lzu!e, c  
public static int getMaxOnlineUser() { J !p,u#"=j  
return maxOnlineUser; UikTn6i  
} OIM<'yFR  
l"x $c  
public static void setMaxOnlineUser(int maxOnlineUser) { nN%.g6v4d  
UserConnectManage.maxOnlineUser = maxOnlineUser; cKs E//  
} oBCkosatx  
kGgeJ aW  
public static long getWaitInterval() { oWeKSe  
return waitInterval; 5/]uf 0T  
} Q+Np^6 D#]  
RFne?  
public static void setWaitInterval(long waitInterval) { L_v"MYjT  
UserConnectManage.waitInterval = waitInterval; \.i)lU  
} >Azv!XoZ-~  
四、调用接口 =V`<z kx  
1oO%v1)d2  
  在需要进入侵检测判断的地方,直接使用UserConnectManage类中的checkLoginValidate方法即可。如EasyJWeb的核心Servlet  :` Xorcw  
L{E:ia  
com.easyjf.web.ActionServlet中调用UserConnectManage的代码: o(Q84p/<  
if(!UserConnectManage.checkLoginValidate(request.getRemoteAddr(),"guest")) dla 9qp3  
{ -BAlp Ll  
info(request,response,new Exception("您对页面的刷新太快,请等待"+UserConnectManage.getWaitInterval()/1000+"秒 oH " z;kO  
 h*#T:Ba  
后再刷新页面!")); dTI0aFty  
return; {Uce5ZRkB  
} ,kOK`B8PR  
五、总结 +,.r'HT  
  当然,这里提供的方法只是一个简单的实现示例,由于上面的用户信息是直接保存在内存中,若并发用户很大的时候的代码的占用,可以考虑引入数据库来记录用户的访问信息,当然相应的执行效率肯定用降低。上面介绍的实现中,入侵检测判断的策略也只有用户访问次数及时间间隔两个元素,您还可以根据你的实现情况增加其它的检测元素。
查看本文来源
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章