<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    憨厚生

    ----Java's Slave----
    ***Java's Host***

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      165 隨筆 :: 17 文章 :: 90 評論 :: 0 Trackbacks
    轉 http://blog.csdn.net/zhaowei001/archive/2007/12/29/2001800.aspx

    作者:EasyJF開源團隊 大峽

    一、簡介

    在Java Web應用程中,特別是網站開發中,我們有時候需要為應用程序增加一個入侵檢測程序來防止惡意刷新的功能,防止非法用戶不斷的往Web應用中重復發送數 據。當然,入侵檢測可以用很多方法實現,包括軟件、硬件防火墻,入侵檢測的策略也很多。在這里我們主要介紹的是Java Web應用程序中通過軟件的方式實現簡單的入侵檢測及防御。

      該方法的實現原理很簡單,就是用戶訪問Web系統時記錄每個用戶的信息,然后進行對照,并根據設定的策略(比如:1秒鐘刷新頁面10次)判斷用戶是否屬于惡意刷新。

    我們的入侵檢測程序應該放到所有Java Web程序的執行前,也即若發現用戶是惡意刷新就不再繼續執行Java Web中的其它部分內容,否則就會失去了意義。這就需要以插件的方式把入侵檢測的程序置入Java Web應用中,使得每次用戶訪問Java Web,都先要到這個入侵檢測程序中報一次到,符合規則才能放行。

      Java Web應用大致分為兩種,一種純JSP(+Java Bean)方式,一種是基于框架(如Struts、EasyJWeb等)的。第一種方式的Java Web可以通過Java Servlet中的Filter接口實現,也即實現一個Filter接口,在其doFilter方法中插入入侵檢測程序,然后再web.xml中作簡單的 配置即可。在基于框架的Web應用中,由于所有應用都有一個入口,因此可以把入侵檢測的程序直接插入框架入口引擎中,使框架本身支持入侵檢測功能。當然, 也可以通過實現Filter接口來實現。

      在EasyJWeb框架中,已經置入了簡單入侵檢測的程序,因此,這里我們以EasyJWeb框架為例,介紹具體的實現方法及源碼,完整的代碼可以在EasyJWeb源碼中找到。

      在基于EasyJWeb的Java Web應用中(如http://www.easyjf.com/bbs/),默認情況下你只要連續刷新頁面次數過多,即會彈出如下的錯誤:

      EasyJWeb框架友情提示!:-):
      您對頁面的刷新太快,請等待60秒后再刷新頁面!
    詳細請查詢http://www.easyjf.com


    二、用戶訪問信息記錄UserConnect.java類  

    這個類是一個簡單的Java Bean,主要代表用戶的信息,包括用戶名、IP、第一次訪問時間、最后登錄時間、登錄次數、用戶狀態等。全部

    代碼如下:

    package com.easyjf.web;

    import java.util.Date;
    /**
    *
    *

    Title:用戶驗證信息


    *

    Description:記錄用戶登錄信息,判斷用戶登錄情況


    *

    Copyright: Copyright (c) 2006


    *

    Company: www.easyjf.com

    >
    * @author 蔡世友
    * @version 1.0
    */
    public class UserConnect {
    private String userName;
    private String ip;
    private Date firstFailureTime;
    private Date lastLoginTime;
    private int failureTimes;//用戶登錄失敗次數
    private int status=0;//用戶狀態0表示正常,-1表示鎖定
    public int getFailureTimes() {
     return failureTimes;
    }
    public void setFailureTimes(int failureTimes) {
     this.failureTimes = failureTimes;
    }
    public Date getFirstFailureTime() {
     return firstFailureTime;
    }

    public void setFirstFailureTime(Date firstFailureTime) {
     this.firstFailureTime = firstFailureTime;
    }

    public String getIp() {
     return ip;
    }

    public void setIp(String ip) {
     this.ip = ip;
    }

    public Date getLastLoginTime() {
     return lastLoginTime;
    }

    public void setLastLoginTime(Date lastLoginTime) {
     this.lastLoginTime = lastLoginTime;
    }

    public String getUserName() {
     return userName;
    }

    public void setUserName(String userName) {
     this.userName = userName;
    }

    public int getStatus() {
     return status;
    }

    public void setStatus(int status) {
     this.status = status;
    }

    }


    三、監控線程UserConnectManage.java類

    這是入侵檢測的核心部分,主要實現具體的入侵檢測、記錄、判斷用戶信息、在線用戶的刷新等功能,并提供其它應用程序使用本組件的調用接口。

    package com.easyjf.web;

    import java.util.Date;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Set;

    import org.apache.log4j.Logger;
    /**
    *
    *

    Title:用戶入侵檢測信息


    *

    Description:用于判斷用戶刷新情況檢查,默認為10秒鐘之內連續連接10次為超時


    *

    Copyright: Copyright (c) 2006


    *

    Company: www.easyjf.com

    >
    * @author 蔡世友
    * @version 1.0
    */
    public class UserConnectManage {
    private static final Logger logger = (Logger) Logger.getLogger(UserConnectManage.class.getName());
    private static int maxFailureTimes=10;//最大登錄失敗次數
    private static long maxFailureInterval=10000;//毫秒,達到最大登錄次數且在這個時間范圍內
    private static long waitInterval=60000;//失敗后接受連接的等待時間,默認1分鐘
    private static int maxOnlineUser=200;//同時在線的最大數
    private final static Map users=new HashMap();//使用ip+userName為key存放用戶登錄信息UserLoginAuth
    private static Thread checkThread=null;
    private static class CheckTimeOut implements Runnable{ 
    private Thread parentThread;
    public  CheckTimeOut(Thread parentThread) 
     {
      this.parentThread=parentThread; 
      synchronized(this){
      if(checkThread==null){   
       checkThread= new Thread(this);
       //System.out.println("創建一個新線程!");
       checkThread.start();   
         }
      }
     } 
     public void run() {  
      while(true)
      {
       if(parentThread.isAlive()){
       try{
       Thread.sleep(2000);
       int i=0;
       if(users.size()>maxOnlineUser)//當達到最大用戶數時清除
       {
        synchronized(users){//執行刪除操作
        Iterator it=users.keySet().iterator();
        Set set=new HashSet();
        Date now=new Date();
        while(it.hasNext())
        {
         Object key=it.next();
         UserConnect user=(UserConnect)users.get(key);
         if(now.getTime()-user.getFirstFailureTime().getTime()>maxFailureInterval)//刪除超時的用戶
         {      
          set.add(key);
          logger.info("刪除了一個超時的連接"+i);
          i++;
         }
        }
        if(i<5)//如果刪除少于5個,則強行刪除1/2在線記錄,犧牲性能的情況下保證內存
        {
         int num=maxOnlineUser/2;
         it=users.keySet().iterator();
         while(it.hasNext() && i
         {      
          set.add(it.next());
          logger.info("刪除了一個多余的連接"+i);
          i++;
         }
        }
        users.keySet().removeAll(set);
        }
       }
       
       }
       catch(Exception e)
       {
        e.printStackTrace();
       }
       
      }
       else
       {   
       break;
       }
      }
      logger.info("監視程序運行結束!"); 
     }
    }
    //通過checkLoginValidate判斷是否合法的登錄連接,如果合法則繼續,非法則執行
    public static boolean checkLoginValidate(String ip,String userName)//只檢查認證失敗次數
    {
     boolean ret=true;
     Date now=new Date(); 
     String key=ip+":"+userName;
     UserConnect auth=(UserConnect)users.get(key);
     if(auth==null)//把用戶當前的訪問信息加入到users容器中
     {
      auth=new UserConnect();
      auth.setIp(ip);
      auth.setUserName(userName);
      auth.setFailureTimes(0);
      auth.setFirstFailureTime(now);
      users.put(key,auth);  
      if(checkThread==null)new CheckTimeOut(Thread.currentThread());
     } 
     else
     {
      if(auth.getFailureTimes()>maxFailureTimes)
      {
               //如果在限定的時間間隔內,則返回拒絕用戶連接的信息
       if((now.getTime()-auth.getFirstFailureTime().getTime())
       {
        ret=false;
        auth.setStatus(-1);
       }
       else  if(auth.getStatus()==-1 && (now.getTime()-auth.getFirstFailureTime().getTime()< (maxFailureInterval+waitInterval)))//重置計數器
       {
        ret=false;
       }
       else    
       {    
        auth.setFailureTimes(0);
        auth.setFirstFailureTime(now);
        auth.setStatus(0);
       }
       
      }
      //登錄次數加1
      auth.setFailureTimes(auth.getFailureTimes()+1);
     }
     //System.out.println(key+":"+auth.getFailureTimes()+":"+ret+":"+(now.getTime()-auth.getFirstFailureTime().getTime()));
     return ret;
    }

    public static void reset(String ip,String userName)//重置用戶信息

     Date now=new Date(); 
     String key=ip+":"+userName;
     UserConnect auth=(UserConnect)users.get(key);
     if(auth==null)//把用戶當前的訪問信息加入到users容器中
     {
      auth=new UserConnect();
      auth.setIp(ip);
      auth.setUserName(userName);
      auth.setFailureTimes(0);
      auth.setFirstFailureTime(now);
      users.put(key,auth);
     } 
     else
     {
      auth.setFailureTimes(0);
      auth.setFirstFailureTime(now);
     }
    }
    public static void remove(String ip,String userName)//刪除用戶在容器中的記錄
    {
     String key=ip+":"+userName;
     users.remove(key);
    }
    public static void clear()//清空容器中內容
    {
     if(!users.isEmpty())users.clear();
    }
    public static long getMaxFailureInterval() {
     return maxFailureInterval;
    }

    public static void setMaxFailureInterval(long maxFailureInterval) {
     UserConnectManage.maxFailureInterval = maxFailureInterval;
    }

    public static int getMaxFailureTimes() {
     return maxFailureTimes;
    }

    public static void setMaxFailureTimes(int maxFailureTimes) {
     UserConnectManage.maxFailureTimes = maxFailureTimes;
    }

    public static int getMaxOnlineUser() {
     return maxOnlineUser;
    }

    public static void setMaxOnlineUser(int maxOnlineUser) {
     UserConnectManage.maxOnlineUser = maxOnlineUser;
    }

    public static long getWaitInterval() {
     return waitInterval;
    }

    public static void setWaitInterval(long waitInterval) {
     UserConnectManage.waitInterval = waitInterval;
    }


    四、調用接口

    在需要進入侵檢測判斷的地方,直接使用UserConnectManage類中的checkLoginValidate方法即可。如EasyJWeb的核心Servlet 

    com.easyjf.web.ActionServlet中調用UserConnectManage的代碼:
       if(!UserConnectManage.checkLoginValidate(request.getRemoteAddr(),"guest"))
           {            
               info(request,response,new Exception("您對頁面的刷新太快,請等待"+UserConnectManage.getWaitInterval()/1000+"秒

    后再刷新頁面!"));
               return;
           }      



    五、總結
    當然,這里提供的方法只是一個簡單的實現示例,由于上面的用戶信息是直接保存在內存中,若并發用戶很大的時候的代碼的占用,可以考慮引入數據庫來記錄用 戶的訪問信息,當然相應的執行效率肯定用降低。上面介紹的實現中,入侵檢測判斷的策略也只有用戶訪問次數及時間間隔兩個元素,您還可以根據你的實現情況增 加其它的檢測元素。

    由于水平有限,該設計上有N不合理或者需要改進的地方,懇請大家指正!



    Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=657199



    posted on 2009-04-17 16:42 二胡 閱讀(213) 評論(0)  編輯  收藏 所屬分類: Javaweb系統開發
    主站蜘蛛池模板: 久久亚洲国产中v天仙www| 国产无人区码卡二卡三卡免费| 国产h视频在线观看网站免费| 亚洲性日韩精品一区二区三区 | 亚洲av无码国产精品色在线看不卡| 亚洲老妈激情一区二区三区| 亚洲第一街区偷拍街拍| 久久久久久久99精品免费 | 国产精品免费看久久久香蕉 | 中文字幕精品三区无码亚洲| 特级无码毛片免费视频尤物| 久久久久亚洲精品男人的天堂| 一级a性色生活片久久无少妇一级婬片免费放 | 国产成人无码区免费内射一片色欲| 真实乱视频国产免费观看| 亚洲精品日韩专区silk| 久久国产精品2020免费m3u8| 日韩电影免费在线观看视频| 亚洲一区影音先锋色资源| 国产成人无码区免费网站| 好看的电影网站亚洲一区| 好吊色永久免费视频大全| 久久99亚洲综合精品首页| eeuss影院www天堂免费| AV在线播放日韩亚洲欧| 国产免费播放一区二区| 在线观看午夜亚洲一区| 水蜜桃视频在线观看免费播放高清| 久久久久久A亚洲欧洲AV冫| 久久这里只精品热免费99| 久久精品国产亚洲AV久| 伊在人亚洲香蕉精品区麻豆| 精品一卡2卡三卡4卡免费视频| 亚洲av永久无码嘿嘿嘿| 亚洲无码黄色网址| **俄罗斯毛片免费| 特级毛片aaaa免费观看| 亚洲美女一区二区三区| 亚洲黄片手机免费观看| 日本h在线精品免费观看| 综合一区自拍亚洲综合图区|