一、简介

在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()

{

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;

}

五、总结

当然,这里提供的方法只是一个简单的实现示例,由于上面的用户信息是直接保存在内存中,若并发用户很大的时候的代码的占用,可以考虑引入数据库来记录用户的访问信息,当然相应的执行效率肯定用降低。上面介绍的实现中,入侵检测判断的策略也只有用户访问次数及时间间隔两个元素,您还可以根据你的实现情况增加其它的检测元素。

java web 网络安全_Java Web中的入侵检测及简单实现相关推荐

  1. java入侵检测源码_Java Web中的入侵检测及简单实现

    作者:EasyJF开源团队 大峡 一.简介 在Java Web应用程中,特别是网站开发中,我们有时候需要为应用程序增加一个入侵检测程序来防止恶意刷新的功能,防止非法用户不断的往Web应用中重复发送数据 ...

  2. java css路径_java web开发中CSS路径有问题吗,运行jsp文件为什么找不到css文件?...

    ---------------------------------------------------------------------------------------------------- ...

  3. java 实现 web 客户端_Java web客户端和服务器端交互的原理

    Java web客户端和服务器端交互的原理 其实HTTP客户端和服务器端的交互原理很简单:即先是浏览器和服务器端建立Socket无状态连接,也就是短连接,然后通过IO流进行报文信息(这个报文是严格遵循 ...

  4. java web环境_java web

    HTTP Status 500 - Request processing failed; nested exception is java.lang.NullPointerException HTTP ...

  5. java web 教程_Java Web服务教程

    java web 教程 Welcome to the Java Web Services Tutorial. Here we will learn about web services, useful ...

  6. java专业编码_java编码中的坑(记一次解决编码BUG的经历) - 贪吃蛇学院-专业IT技术平台...

    1.2016年11月15日(周二),我被经理外派出差渝北金开大道,任务:解决那边的一个数据库乱码异常 2.那边的负责人描述:数据库原是utf8编码,他为了兼容emoji表情,改为utf8mb4,之后出 ...

  7. java h2数据库_JAVA 项目中使用 H2 数据库

    JAVA 项目中使用 H2 数据库 发布时间:2018-06-08 15:43, 浏览次数:823 , 标签: JAVA 为什么要使用H2数据库 H2数据库是可以嵌入到JAVA项目中的,因为只需要导入 ...

  8. 计算机网络安全中应用入侵检测技术

    1.计算机网络常见入侵方式 针对计算机网络的入侵主要指通过相应计算机程序在物理设施上进行的破坏,又或者编写的程序代码或计算机指令实现对未授权文件或网络的非法访问.继而入侵至网络中的行为.当前常见的计算 ...

  9. java的成员方法_java编程中的成员方法是什么?

    DIEA 成员方法描述对象所具有的功能或操作,反映对象的行为,是具有某种相对独立功能的程序模块.它与过去所说的子程序.函数等概念相当.一个类或对象可以有多个成员方法,对象通过执行它的成员方法对传来的消 ...

  10. java runnable 异常_JAVA 线程中的异常捕获

    在java多线程程序中,所有线程都不允许抛出未捕获的checked exception(比如sleep时的InterruptedException),也就是说各个线程需要自己把自己的checked e ...

最新文章

  1. TreeView复选框选择逻辑判断
  2. Java报告比较日期,java 比较两个日期大小(1)
  3. linux格式化大于2t硬盘分区,linux下大于2tb硬盘格式化及挂载,linux下大于2t的分区方法,linux gpt分区表 管理 自动挂载分区...
  4. Android Gradle Plugin 源码解析之 externalNativeBuild
  5. 【转】Java内存与垃圾回收调优
  6. 嵌入式Linux系统基础知识
  7. SEL selector (二)
  8. python归并排序算法实现_python算法实现系列-归并排序
  9. 探秘亚洲最大单体智慧农园:探索改变农民“靠天吃饭”的农作模式
  10. 彩色烟雾一直是许多摄影师和摄影爱好者的首选武器
  11. SharePoint Portal Server之常见问题
  12. mysql搜索结果去重_MySQL去除查询结果重复
  13. php实现中间件6,THINKPHP6 实现中间件
  14. 12,三维Panel
  15. 用MP3或WAV制作人声铃声的简单教程
  16. matlab计算一组数的函数值_「数学建模」MATLAB的数值计算
  17. 如何用Word打开PDF文件?
  18. 软件测试基本流程与方案(以电商大促为例)
  19. 制作纯净系统U盘教程(详细版)
  20. Freemarker函数

热门文章

  1. 程序员如何切入区块链去中心化应用开发 1
  2. 【Java学习笔记之三】java中的变量和常量
  3. EmEditor中正则表达式
  4. Exchange+SP2的安装
  5. 使用C#代码实现增加用户帐号
  6. 时间+地区 选择器
  7. SpringBoot+zk+dubbo架构实践(二):SpringBoot 集成 zookeeper
  8. 微信小程序自定义组件(Toast)
  9. java 静态变量锁_线程中锁方法和静态变量的锁
  10. 全网首发:ProGuard保持一个类名函数名需要加public