当前位置:   article > 正文

使用Java定时从Nginx的日志中获取黑客的ip并加入访问黑名单_mstshash=administr

mstshash=administr

简介

最近发现公司线上的应用老出现访问异常的情况,排查nginx的access.log日志文件,发现了大量恶意攻击的代码,内容如下
在这里插入图片描述
主要内容为"\x03\x00\x00/*\xE0\x00\x00\x00\x00\x00Cookie: mstshash=Administr" 400 173 “-” “-”
一般黑客的ip地址查询都是在国外的
在这里插入图片描述

使用nginx的deny属性禁止黑名单IP访问

然后想起用nginx的ip黑名单来限制
在这里插入图片描述

在nginx.conf配置文件中http标签中加入

 #把94.232.40.111列入黑名单
 deny 94.232.40.111;

  • 1
  • 2
  • 3

由于在nginx.conf中直接写入deny代码不怎么优雅,把信息提取成一个配置文件中
在nginx.conf文件的路径同级写入一个blackListIp.conf文件
在这里插入图片描述
blackListIp.conf文件内容如下

 deny 94.232.40.111;
  • 1

在nginx中的http标签中引入黑名单配置文件

http {
    #屏蔽黑名单IP
    include blackListIp.conf;
}
  • 1
  • 2
  • 3
  • 4

在这里插入图片描述

运行一段时间发现还是会出现nginx被恶意攻击宕机了,后面查看nginx的access.log日志发现了大量模式的黑客IP,再排查error.log内容如下
在这里插入图片描述
关键信息 access forbidden by rule 是拒绝访问意思,表示黑名单是生效了

但是手动去access.log日志找黑客IP然后加入黑名单配置文件太麻烦,于是手撸了一个java工具类解决此问题.

Java工具类

1.定义恶意攻击代码信息列表

可以根据需求自行扩展

 	/**
     * 自定义匹配恶意攻击的信息
     */
    private static final List<String> MATCHER_LIST = Arrays.asList("mstshash=Administr");
  • 1
  • 2
  • 3
  • 4

2.解析nginx日志中的非法访问的IP地址

   /**
     * 解析nginx日志中的非法访问的IP地址
     * @param logPath
     * @return 非法IP地址
     * @throws Exception
     */
    private static Set<String> readNginxAccess(String logPath) throws Exception {
        File file = new File(logPath);
        if (!file.exists()) {
            logger.error("{} not exists", logPath);
            return null;
        }

        Set<String> set = new HashSet<>();
        InputStreamReader ir = new InputStreamReader(new FileInputStream(file));
        LineNumberReader input = new LineNumberReader(ir);
        String line;

        while ((line = input.readLine()) != null) {
            final String fLine = line;
            for (String str : MATCHER_LIST) {
             	//如果匹配上了,把ip加入set集合并结束for循环
                if (fLine.contains(str)) {
                    System.out.println(fLine);
                    set.add(fLine.split(" ")[0]);
                    break;
                }
            }
        }
        return set;
    }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

3.写入nginx的黑名单文件中

    /**
     * 换行符
     */
    private static String lineSeparator = "\r\n";

    /**
     * 日期格式
     */
    private final static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy_MM_dd_HH_ss");

    /**
     * 写入黑名单列表
     * @param blackListConfigPath 黑名单配置文件路径
     * @param blackListSet        扫描出来的黑客ip集合
     * @return (如果扫描出来的黑客IP地址和已存在的不完全重叠, 返回true, 否则false)
     * @throws Exception
     */
    private static boolean writeBlacklist(String blackListConfigPath, Set<String> blackListSet) throws Exception {
        File file = new File(blackListConfigPath);
        if (!file.exists()) {
            file.createNewFile();
        }
        List<String> list = new ArrayList<>();
        InputStreamReader ir = new InputStreamReader(new FileInputStream(file));
        LineNumberReader input = new LineNumberReader(ir);
        String line;
        String ip;
        while ((line = input.readLine()) != null) {
            if ("".equals(line.trim()) || line.startsWith("#")) {
                continue;
            }
            ip = line.split(" ")[1];
            ip = ip.substring(0, ip.length() - 1);
            list.add(ip);
        }
        //遍历添加黑名单列表中不存在的IP
        Set<String> filterSet = new HashSet();
        blackListSet.forEach(ipaddr -> {
            if (!list.contains(ipaddr)) {
                filterSet.add(ipaddr);
            }
        });
        if (filterSet.size() > 0) {
            FileWriter out = new FileWriter(file, true);
            BufferedWriter bw = new BufferedWriter(out);
            for (String ipaddr : filterSet) {
                bw.write(lineSeparator);
                bw.write(String.format("deny %s;", ipaddr));
                logger.info("黑客IP:{} 已写入nginx黑名单列表", ipaddr);
            }
            //写入文件修改时间
            bw.write(lineSeparator);
            bw.write("#" + simpleDateFormat.format(new Date()));
            bw.flush();
            bw.close();
            return true;
        } else {
            logger.info("未发现新的黑客IP地址");
            return false;
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

4.工具类集成方法

  • 1.先找到非法访问IP的列表
  • 2.把获取列表信息写入nginx的黑名单配置文件
  • 3.如果写入成功,则备份access.log文件,然后执行nginx -s reload命令刷新配置文件
    /**
     * 扫描黑名单
     * @param logPath       access.log文件的路径
     * @param blackListPath 黑名单配置文件路径
     * @param binPath       nginx的启动文件路径
     * @throws Exception
     */
    public static void scanningBlackList(String logPath, String blackListPath, String binPath) throws Exception {
        //第一步 找到非法访问IP
        Set<String> set = NginxUtil.readNginxAccess(logPath);
       if (set!=null && set.size() > 0) {
            //第二步,写入非法IP进nginx的blackList文件
            boolean flag = NginxUtil.writeBlacklist(blackListPath, set);
            //第三步,备份之前的access.log,刷新nginx配置使黑名单生效
            if (flag) {
                //备份nginx日志文件
                String backUpLogPath = logPath + "_backup_" + simpleDateFormat.format(new Date());
                Process process = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", String.format("mv %s %s", logPath, backUpLogPath)}, null, null);
                process.waitFor();
                //执行 /usr/local/nginx/nginx -s reload 会重新生成一个新的access.log文件
                process = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", String.format("%s -s reload", binPath)}, null, null);
                process.waitFor();
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

5.测试Main函数

下面通过使用java源生的定时任务线程池**(scheduledThreadPool** )来执行任务,如果不需要集成了web应用中,则下面的代码打包完放在服务器上面运行就可以了,如果需要集成到web应用中,则请查看下面的步骤6

    public static void main(String[] args) throws Exception {
        //nginx的工作空间
        String nginxPath = "/usr/local/nginx/";
        //nging的access.log路径
        String logPath = nginxPath + "logs/access.log";
        //黑名单配置文件路径
        String blackListPath = nginxPath + "conf/blackListIp.conf";
        //启动脚本文件路径
        String binPath = nginxPath + "bin/nginx";
        //使用单线程线程池执行定时任务
        ScheduledExecutorService scheduledThreadPool = Executors.newSingleThreadScheduledExecutor();
        //应用启动10秒后,每隔30秒执行一次任务
        scheduledThreadPool.scheduleAtFixedRate(()->{
            try {
                scanningBlackList(logPath, blackListPath, binPath);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, 10, 30, TimeUnit.SECONDS);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

6.扩展到springboot应用里使用

配置文件

application.yml

nginx:
  #恶意攻击的内容,多组用 , 隔离
  matcher_list: mstshash=Administr,\x16\x03\x01\x00{
  #工作空间
  workspace: /usr/local/nginx/
  #启动脚本
  sbin: ${nginx.workspace}sbin/nginx
  #日志文件
  log: ${nginx.workspace}logs/access.log
  #黑名单IP存储文件
  blackListIp: ${nginx.workspace}conf/blackListIp.conf

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

配置类

@Configuration
@ConfigurationProperties(prefix = "nginx")
public class NginxParam {
    private String sbin;
    private String log;
    private String blackListIp;
    private List<String> matcherList;
   //省略get set
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

定时任务类

@Component
public class NginxScheduling {

    @Autowired
    NginxParam nginxParam;
	
	 /**
     * bean加载的时候执行的初始化操作
     */
    @PostConstruct
    public void init() {
        NginxUtil.setMatcherList(nginxParam.getMatcherList());
    }
	
    /**
     * 扫描非法IP
     * 每隔30秒扫描一次非法IP并加入黑名单
     */
    @Scheduled(fixedDelay = 30000)
    public void ScanForIllegalIP() throws Exception {
        NginxUtil.scanningBlackList(nginxParam.getLog(),nginxParam.getBlackListIp(),nginxParam.getSbin());
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

nginx工具类

基于之前定义的NginxUtil工具类,新增一个setMatcherList方法,把配置文件定义的恶意攻击的信息注入到工具类中

public class NginxUtil {
/**
     * 自定义匹配恶意攻击的信息
     */
    private static List<String> MATCHER_LIST;
    public static void setMatcherList(List<String> matcherList) {
        MATCHER_LIST = matcherList;
    }
   }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

启动类添加开启定时任务注解

@SpringBootApplication
@EnableScheduling
public class GuardApplication {
    public static void main(String[] args) {
        SpringApplication.run(GuardApplication.class, args);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

扩展功能,检测nginx进程宕机了自动重启

如果没这个需要就忽略下面代码。
配置文件新增属性

nginx:
  #nginx部署的某个服务端口
  pingPort: http://127.0.0.1:38888
  • 1
  • 2
  • 3

在NginxParam配置类新增pingPort字段

public class NginxParam {
	private String pingPort;
}
  • 1
  • 2
  • 3

在NginxUtil工具类中添加以下代码

public class NginxUtil {
     /**
     * 监测nginx进程是否存活
     */
    public static void monitor(String bin, String pingPort) {
        try {
            //执行 curl访问nginx启动的某个端口,如果不存在则表示nginx已经挂了
            Process process = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", "curl " + pingPort}, null, null);
            InputStreamReader isr = new InputStreamReader(process.getErrorStream());
            BufferedReader br = new BufferedReader(isr);
            String line;
            StringBuilder sb = new StringBuilder();
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            process.waitFor();
            String res = sb.toString();
            if (StringUtils.hasLength(res) && res.contains("Connection refused")) {
                logger.info("nginx process abnormal,restart ....");
                process = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", bin}, null, null);
                process.waitFor();
            } else {
                logger.info("nginx process normal");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

在定时任务类中添加新任务,一分钟检测一次nginx心跳,如果nginx宕机了就自动重启

@Component
public class NginxScheduling {
  /**
     * 健康监测
     * @throws Exception
     */
    @Scheduled(fixedDelay = 60000)
    public void healthMonitoring()  {
        NginxUtil.monitor(nginxParam.getSbin(),nginxParam.getPingPort());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

实战效果

查看nginx的log目录,发现备份文件多了几个,代表着已经有新的黑客IP被列入黑名单了
在这里插入图片描述
查看/usr/local/nginx/conf/blackListIp.conf文件发现已经新增了几个IP了,代表着任务已经完成了.

在这里插入图片描述

配套代码地址

gitee地址
配套代码里在博客里的功能基础上加入了监控nginx进程宕机了重启的功能和把国外的IP地址访问拉入黑名单功能。

要是觉得我写的对你有点帮助的话,麻烦在gitee上帮我点 Star

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/702623
推荐阅读
相关标签
  

闽ICP备14008679号