把Apache ModSecurity的攻击日志存储到MySQL

把Apache ModSecurity的攻击日志存储到MySQL。 查看mod_security文件类型的日志,确实太麻烦了。国内资料居然没有百度到,找到了一篇英文文章,并且php都是写好的。

 

httpd.conf

<IfModule security2_module>
  Include conf/modsecurity-crs/crs-setup.conf
  Include conf/modsecurity-crs/rules/*.conf

  # mlogc.exe 配置文件
  SecDataDir logs
  SecAuditEngine RelevantOnly
  SecAuditLogRelevantStatus "^(?:5|4\d[^4])"
  SecAuditLogType Concurrent
  SecAuditLogParts ABCDEFGHZ
  SecAuditLogStorageDir logs/mod_security/
  SecAuditLog "|${SRVROOT}/bin/mlogc.exe d:/ap/apache/conf/mlogc.conf"
  # SecAuditLog "|${SRVROOT}/bin/mlogc.exe"
</IfModule>

 

mlogc.conf

CollectorRoot       "d:/ap/apache/logs"
ConsoleURI          "http://localhost:9001/test/mlogc.php"
SensorUsername      "USERNAME"
SensorPassword      "PASSWORD"
LogStorageDir       "mod_security"
TransactionLog      "mlogc-transaction.log"
QueuePath           "mlogc-queue.log"
ErrorLog            "mlogc-error.log"
LockFile            "mlogc.lck"
KeepEntries         0
ErrorLogLevel       2
MaxConnections      10
MaxWorkerRequests   1000
TransactionDelay    50
StartupDelay        5000
CheckpointInterval  15
ServerErrorTimeout  60


数据库脚本

CREATE DATABASE IF NOT EXISTS `mlogc` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci;
USE `mlogc`;

CREATE TABLE IF NOT EXISTS `data` (
  `ID` int(11) NOT NULL,
  `Continuation` int(1) NOT NULL,
  `PartA` mediumtext NOT NULL,
  `PartB` mediumtext,
  `PartC` mediumtext,
  `PartD` mediumtext,
  `PartE` mediumtext,
  `PartF` mediumtext,
  `PartG` mediumtext,
  `PartH` mediumtext,
  `PartI` mediumtext,
  `PartJ` mediumtext,
  `PartK` mediumtext,
  `PartZ` mediumtext NOT NULL,
  `RawText` mediumblob NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

ALTER TABLE `data`
  ADD PRIMARY KEY (`ID`);

ALTER TABLE `data`
  MODIFY `ID` int(11) NOT NULL AUTO_INCREMENT;


PHP脚本

<?php
if($_SERVER['REQUEST_METHOD'] == 'PUT') {
    // The username and password setup in mlogc.conf
    $username = "admin";
    $password = "password";
    // The DB username and password
    $dbUname = "USERNAME";
    $dbPasswd = "PASSWORD";

    if($username !== $_SERVER['PHP_AUTH_USER'] or $password !== $_SERVER['PHP_AUTH_PW']){
        error_log("Failed Login Attempt to MLogc PHP Console - Username:" . $_SERVER['PHP_AUTH_USER'], 0);
        die("The username or password was incorrect");
    }
    $dsn = 'mysql:host=localhost;dbname=mlogc';
    $options = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'); 
    $dbh = new PDO($dsn, $dbUname, $dbPasswd, $options);
    $putdata = fopen("php://input", "r");
    $continuation = 0;
    // This may take at most 16MB, we are just being safe
    while ($data = fread($putdata, 15360)){
        $lookup = array("A","B","C","D","E","F","G","H","I","J","K","Z");
          $audit_parts = array_fill(0,sizeof($lookup),"NULL");
          // Analyze data to make sure its of the expected format
          $audit_log = explode("\n", $data);
          $current = 0;
          foreach ($audit_log as $line){
            // If we are at the beginning
            if(substr($line,0,2) === "--" && substr(str_replace(array("\r", "\n"), '', $line),-2,2) == "--"){
                $current = array_search(substr(str_replace(array("\r", "\n"), '', $line),-3,1),$lookup);
                // We are unable to find the key
                if($current === false){
                    error_log("An invalid Audit Log Part was specified",0);
                    die("An invalid audit log part was specified this will not be saved");    
                }
                $audit_parts[$current] = $line;
            }else{
                $audit_parts[$current] = $audit_parts[$current] . '\n' . $line;
            }
             }
        if($audit_parts[11] === "NULL"){
            error_log("The format received does not appear correct",0);
            die("The format received does not appear correct");
             }
         $stmt = $dbh->prepare("INSERT INTO data (Continuation,PartA,PartB,PartC,PartD,PartE,PartF,PartG,PartH,PartI,PartJ,PartK,PartZ,RawText) VALUES (:continue,:a,:b,:c,:d,:e,:f,:g,:h,:i,:j,:k,:z,:data)");
        $stmt->bindParam(':a', $audit_parts[0]);
        $stmt->bindParam(':b', $audit_parts[1]);
        $stmt->bindParam(':c', $audit_parts[2]);
        $stmt->bindParam(':d', $audit_parts[3]);
        $stmt->bindParam(':e', $audit_parts[4]);
        $stmt->bindParam(':f', $audit_parts[5]);
        $stmt->bindParam(':g', $audit_parts[6]);
        $stmt->bindParam(':h', $audit_parts[7]);
        $stmt->bindParam(':i', $audit_parts[8]);
        $stmt->bindParam(':j', $audit_parts[9]);
        $stmt->bindParam(':k', $audit_parts[10]);
        $stmt->bindParam(':z', $audit_parts[11]);
        $stmt->bindParam(':data', $data);
        $stmt->bindParam(':continue',$continuation);
        $stmt->execute();
        // If we need to run through again, its a continuation
        $continuation = 1;
    }
    fclose($putdata);
}else{
    die("This application does not respond to such requests");
}

?>


参考:
https://www.trustwave.com/Resources/SpiderLabs-Blog/Sending-ModSecurity-Logs-to-MySQL/

https://www.feistyduck.com/library/modsecurity-handbook-free/online/ch04-logging.html

https://sourceforge.net/p/mod-security/mailman/mod-security-users/?viewmonth=200901

声明:本站所有文章和图片,如无特殊说明,均为原创发布。商业转载请联系作者获得授权,非商业转载请注明出处。
随机推荐
JavaScript 使用 html2canvas 生成图片
WordPress 插件路径相关
MySQL 的 sql_mode 模式介绍:为什么 MySQL 中 int,float,double 类型字段插入空字符时自动转为0
WordPress 函数 add_option()、get_option() 和 update_option()
JavaScript 使用剪切板
JavaScript 自定义属性 dataset
WordPress 常用接口
Content Security Policy(CSP)简介