• inotify-tools + php脚本实现Linux服务器文件监控并邮件提醒


      需求简介:

      由于服务器被挂马,经常被写入涉敏感的html网页,领导时常被网监请去喝茶,呵呵你懂的。所以有两个需求,一是找出服务器的木马后门和修复代码漏洞,二是监控服务器涉及增删改查的文件。

      第一个不在此次探讨行列,故只说第二个需求。

      inotify简介:

       Inotify 是一个 Linux特性,它监控文件系统操作,比如读取、写入和创建。Inotify 反应灵敏,用法非常简单,并且比 cron 任务的繁忙轮询高效得多。学习如何将 inotify 集成到您的应用程序中,并发现一组可用来进一步自动化系统治理的命令行工具。(来自百度百科 inotify

      inotify-tools是简化使用inotify服务的一种工具。

      以下,我们开始安装inotify-tools。

      服务器系统:centos 6.5
      文件目录:/data/rise
      实现目的:当/data/rise目录下任何文件发生变化时,记录日志并保存。
     
      具体操作:
     
    一、安装inotify-tools工具
     
    1、查看服务器内核是否支持inotify服务
     
      命令:ll /proc/sys/fs/inotify   #列出文件目录,出现下面内容,说明服务器支持
     
     
    备注:Linux下支持inotify的内核最小为2.6.13,可以输入命令 [ uname -a ] 查看,centOS 5.x 内核为2.6.32,默认已经支持inotify
     
     
    2、安装inotify-tools工具
     
    yum install make gcc gcc-c++   #安装编译工具
     
      inotify-tools下载地址:点我下载
     
      上传inotify-tools-3.14.tar.gz到/usr/local/src目录下。
      
    cd /usr/local/src
    
    tar -zxvf inotify-tools-3.14.tar.gz  #解压
    
    cd inotify-tools-3.14    #进入解压目录
    
    ./configure --prefix=/usr/local/inotify    #配置
    
    make   #编译
    
    make install   #安装
     
    3、设置环境变量
     
    echo "PATH=/usr/local/inotify/bin:$PATH" >>/etc/profile.d/inotify.sh
    
    source /etc/profile.d/inotify.sh    #使设置立即生效
    
    echo "/usr/local/inotify/lib" >/etc/ld.so.conf.d/inotify.conf
    
    ln -s /usr/local/inotify/include /usr/include/inotify
     
    4、修改inotify默认参数(inotify默认内核参数太小)
    执行以下命令查看结果:

    sysctl -a | grep max_queued_events #结果是:fs.inotify.max_queued_events = 16384 sysctl -a | grep max_user_watches #结果是:fs.inotify.max_user_watches = 8192 sysctl -a | grep max_user_instances #结果是:fs.inotify.max_user_instances = 128 #修改上述参数为下列值 sysctl -w fs.inotify.max_queued_events="99999999" sysctl -w fs.inotify.max_user_watches="99999999" sysctl -w fs.inotify.max_user_instances="65535" #修改方法 vi /etc/sysctl.conf #添加以下代码 fs.inotify.max_queued_events=99999999 fs.inotify.max_user_watches=99999999 fs.inotify.max_user_instances=65535 wq! #保存退出
    参数说明:
     
    max_queued_events:
     
    inotify队列最大长度,如果值太小,会出现"** Event Queue Overflow **"错误,导致监控文件不准确
     
     
     
     
     
     
    max_user_watches:
      要同步的文件包含多少目录,可以用:find /data/rise -type d | wc -l 统计,必须保证max_user_watches值大于统计结果(这里/data/rise为同步文件目录)
     
    max_user_instances:
      每个用户创建inotify实例最大值
     
    二、创建实时脚本(可跳过走第三步
     
    mkdir -p /home/inotify   #创建目录
    
    vim /home/inotify/inotif.sh  #编辑并添加以下内容
    
        #!/bin/sh
          /usr/local/inotify/bin/inotifywait -mrq -e modify,create,move,delete --fromfile '/home/inotify/excludedir' --timefmt '%y-%m-%d %H:%M' --format '%T %f %e'
    /data/rise/ >> /tmp/rsync.txt
    
    wq!     #保存退出
    
    vim /home/inotify/excludedir    #编辑并添加以下内容
    
     /data/rise/     #要监控的目录
     @/data/rise/cache/   #要排除监控的目录
    
    wq!     #保存退出
    
    chmod +x /home/inotify/inotif.sh      #添加执行权限
    
    vim /etc/rc.d/rc.local      #编辑并在最后一行添加以下内容,开机自动启动
    
      sh /home/inotify/inotif.sh
    
    wq!     #保存退出

    reboot重启生效
    三、直接使用手动执行命令(不想创建脚本可以走这一步
     
    切换到有inotifywait的目录下或直接在命令中添加文件路径。
     
    命令如下:
    /usr/local/inotify/bin/inotifywait  -m -r -d -o /tmp/file_change.log  --timefmt '%F %T' --format '%T %w%f %e'  -e close_write -e create  /data/riseweb/   @/data/riseweb/data/  @/data/riseweb/riseimg/

    命令解析:

    /tmp/file_change.log 是日志路径,生成的日志写在这里面。
    /data/riseweb/ 是监控的文件目录,后面两个@是要排除监控的目录。

    四、使用PHP脚本监测并发送邮件

    实现思路:

      在/tmp文件夹下新建一个row_mark.txt的文件,用来保存上一次的file_change.log的最后行数,在crontab中定时执行php脚本,获取file_change.log的最后行数,与row_mark文件最后保存的行数做对比,数字一致,说明没有新增操作日志。不一致,说明有新增操作日志,读取新行数与旧行数之间的日志内容,排版发送邮件,并把新行数写入row_mark.txt文件。

    实现的php脚本代码:

    <?php
    /**
     * Created by PhpStorm.
     * User: jimmyRen
     * Date: 16/10/24
     * Time: 下午1:56
     * 主要作用:检查服务器项目目录下是否有新建文件或文件夹,如果有,发送邮件通知
     * 实现思路:服务器如有新建文件,inotify会写在/tmp/file_change.log里,打开文件,获取最后一行的行数,如果大于0或大于上一次保存的行数,则追加写进行数文件中,并发送邮件通知
     */
    
    require_once(dirname(__FILE__)."/include/common.inc.php");
    date_default_timezone_set("PRC");
    $url = '/tmp/';
    //打开日志文件
    $change_log = file_get_contents($url.'file_change.log');
    //打开记录行数的文件
    $row_log = file_get_contents($url.'row_mark.log');
    //将文件以每行转换成数组
    $change_array = explode("
    ",$change_log);
    $row_array = explode("
    ",$row_log);
    //获取数组的总长度
    $change_count = count($change_array);
    $row_count = count($row_array);
    //获取日志文件最后一行的key[行数]
    $change_row = $change_count - 2;
    //获取行数文件最后一行的值
    $row_value = substr($row_array[$row_count-1],0,strpos($row_array[$row_count-1],"["));
    
    $row_date = date("Y-m-d H:i:s",time());
    if($change_row > 0 && $row_log== ""){//第一次写行数日志
        $file_write = file_put_contents($url.'row_mark.log',$change_row."[".$row_date."]",FILE_APPEND);
        echo "首次写入记录成功";exit;
    }elseif($change_row > 0 && $change_row > $row_value){
        $file_write2 = file_put_contents($url.'row_mark.log',"
    ".$change_row."[".$row_date."]",FILE_APPEND);
    }else{
        echo "当前时间".date("Y-m-d H:i:s", time())."  没有新写入的文件";
        exit;
    }
    
    //有新写入的行数,把日志新写入的内容循环取出来,生成文件,然后发送email
    if($file_write2){
        ini_set("memory_limit","512M");
        $new_array = array();
        for($i = $row_value;$i<$change_row;$i++){
            $new_array[] = "
    
    ".$change_array[$i];
        }
        //把拿到的数组转换成行数格式的字符串
        $text = implode("
    
    ",$new_array);
        $file_time = date("Y-m-d_H:i");
        //把内容生成文件
        $file = fopen($url."checkChangeLog".$file_time.".txt","w+");
        if($file){
            iconv("UTF-8","GB2312//IGNORE",$text);
            $write = fwrite($file,$text);
        }
        fclose($file);
    
        //发送邮件
        function sendmail($email, $mailtitle, $mailbody)
        {
            global $cfg_sendmail_bysmtp, $cfg_smtp_server, $cfg_smtp_port, $cfg_smtp_usermail, $cfg_smtp_user, $cfg_smtp_password, $cfg_adminemail,$cfg_webname;
            if($cfg_sendmail_bysmtp == 'Y' && !empty($cfg_smtp_server))
            {
                $mailtype = 'TXT';
                require_once(DEDEINC.'/mail.class.php');
                $smtp = new smtp($cfg_smtp_server,$cfg_smtp_port,true,$cfg_smtp_usermail,$cfg_smtp_password);
                $smtp->debug = false;
                if(!$smtp->smtp_sockopen($cfg_smtp_server)){
                    ShowMsg('邮件发送失败,请联系管理员','-1');
                    exit();
                }
                $smtp->sendmail($email,$cfg_webname,$cfg_smtp_usermail, $mailtitle, $mailbody, $mailtype);
            }else{
                @mail($email, $mailtitle, $mailbody, $headers);
            }
        }
        
        $email = "906691xxx.qq.com";  //这里填写要发送到的邮箱
        $mailtitle = date("Y-m-d H:i", time())." rise文件写入情况";
        $mailbody = $text;
        sendmail($email, $mailtitle, $mailbody);
        echo "脚本执行成功!";exit;
    
    }

    tip:记得加载发送邮件的class。 

    五、crontab定时任务

      要求是每天的0 - 7点,每5个小时执行一次,7 - 21点,每1个小时执行一次,21 - 23点,每2个小时执行一次,故crontab脚本命令如下。

    #定时检查服务器文件写入情况并发送邮件通知
    0 0-7/5,7-21/1,21-23/2 * * * php /data/rise/checkfile.php

    六、总结

      需求肯定是实现了,由于不是专业的运维,本次只是实现了需求,大神们有更好的方法可交流探讨。

    
    
  • 相关阅读:
    微信小程序开发
    layer 弹出框的使用
    [转]如何把别人项目代码修改后 提交到github
    [转载]Github轻松上手1-Git的工作原理与设置
    [学]git 原理学习
    Dynamics CRM Form表单中通过javascript抓取触发change事件字段的属性名
    技巧:多共享动态库中同名对象重复析构问题的解决方法
    The encryption certificate of the relying party trust identified by thumbprint is not valid
    Cannot start service MSSQL$MICROSOFT##WID on computer
    Hive操作语句实例讲解(帮助你了解 桶 bucket)
  • 原文地址:https://www.cnblogs.com/spareribs/p/7722453.html
Copyright © 2020-2023  润新知