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

简介

最近发现公司线上的应用老出现访问异常的情况,排查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;

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

 deny 94.232.40.111;

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

http {
    #屏蔽黑名单IP
    include blackListIp.conf;
}

在这里插入图片描述

运行一段时间发现还是会出现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");

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;
    }

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;
        }
    }

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();
            }
        }
    }

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);
    }

6.扩展到springboot应用里使用

配置文件

application.yml

nginx:
  #工作空间
  workspace: /usr/local/nginx/
  #启动脚本
  sbin: ${nginx.workspace}sbin/nginx
  #日志文件
  log: ${nginx.workspace}logs/access.log
  #黑名单IP存储文件
  blackListIp: ${nginx.workspace}conf/blackListIp.conf

配置类

@Configuration
@ConfigurationProperties(prefix = "nginx")
public class NginxParam {
    private String sbin;
    private String log;
    private String blackListIp;
   //省略get set
}

定时任务类

@Component
public class NginxScheduling {

    @Autowired
    NginxParam nginxParam;

    /**
     * 扫描非法IP
     * 每隔30秒扫描一次非法IP并加入黑名单
     */
    @Scheduled(fixedDelay = 30000)
    public void ScanForIllegalIP() throws Exception {
        NginxUtil.scanningBlackList(nginxParam.getLog(),nginxParam.getBlackListIp(),nginxParam.getSbin());
    }

}

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

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

}

实战效果

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

在这里插入图片描述

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 创作都市 设计师:CSDN官方博客 返回首页