Apache - mod_security

最後更新: 2022-11-30

介紹

mod_security =WAF - application firewall

HomePage: http://www.modsecurity.org/documentation/
 

功能

  • 抵擋 SQL injection attacks, cross-site scripting, path traversal attacks
  • HTTP Denial of Service Protections
  • Detecting common web application security attack
  • Integration with AV Scanning for File Uploads
  • Tracking Sensitive Data - Tracks Credit Card usage and blocks leakages
  • Identification of Application Defects

目錄

 


與 mod_rewrite 比較

 

modsecurity 可以處理 POST

modsecurity response 內容 (server output)

modsecurity 支援 Block Brute-Froce Attacks

Notes

mod_rewrite will not work on POST parameters.

原因: the parameters of a POST request are found within the request body

GET 情況用 "QUERY_STRING"

 


Installation

 

C6 /C7

yum install mod_security

Module

C7

/etc/httpd/conf.modules.d/10-mod_security.conf

LoadModule security2_module modules/mod_security2.so

<IfModule !mod_unique_id.c>
    LoadModule unique_id_module modules/mod_unique_id.so
</IfModule>

 * Make sure you have mod_unique_id installed. mod_unique_id is packaged with Apache httpd.

/etc/httpd/conf.d/mod_security.conf

...
Include modsecurity.d/*.conf
Include modsecurity.d/activated_rules/*.conf
...

 


Basic Settings

 

/etc/httpd/conf.d/mod_security.conf

<IfModule mod_security2.c>
    SecRuleEngine DetectionOnly
    SecRequestBodyAccess Off
    SecResponseBodyAccess Off

    SecPcreMatchLimit 1000
    SecPcreMatchLimitRecursion 1000
    SecTmpDir /var/lib/mod_security
    SecDataDir /var/lib/mod_security
</IfModule>

DetectionOnly(log only)

# Settings: on / off / DetectionOnly

SecRuleEngine DetectionOnly

SecPcreMatchLimit 1500                             # Default

Description: Sets the match limit in the PCRE library.

SecPcreMatchLimitRecursion 1500               # Default

Description: Sets the match limit recursion in the PCRE library.

SecTmpDir /var/lib/mod_security

As of ModSecurity version 3.0, SecTmpDir is no longer supported.

libModSecurity is able to deal with request body in a file or in a buffer (chunked or not).

(e.g. nginx 's client_body_buffer_size)

Supported on libModSecurity: No

SecDataDir /var/lib/mod_security

Description: Path where persistent data (e.g., IP address data, session data, and so on) is to be stored.

The directory to which the directive points must be writable by the web server user.

Supported on libModSecurity: No

Default Action

當中 rule 時出 HttpStatusCode 417

SecDefaultAction "phase:1,nolog,auditlog,deny,status:417"
SecDefaultAction "phase:2,nolog,auditlog,deny,status:417"
SecDefaultAction "phase:3,nolog,auditlog,deny,status:417"
SecDefaultAction "phase:4,nolog,auditlog,deny,status:417"

 * status 不可以撞 nginx 內置那些, 比如 444, 499

Remark: log 的組合

  • nolog,noauditlog
  • log,auditlog

Bodiy Check

Whether request bodies will be buffered and processed by ModSecurity

SecRequestBodyAccess Off

Whether response bodies are to be buffered

# This is only neccessary if data leakage detection and protection is required.

SecResponseBodyAccess Off

 

 * 改完 settings / rules 要 service httpd reload

 


Disable "mod_security" Per Folder

 

SecRuleEngine, SecRequestBodyAccess, SecRule

Scope: Any

# For a particular directory:

<Directory "/var/www/wp-admin">
    <IfModule security2_module>
        SecRuleEngine Off
    </IfModule>
</Directory>

OR

# Remove a particular rule

<LocationMatch "/wp-admin/update.php">
    <IfModule security2_module>
        SecRuleRemoveById 981173
    </IfModule>
</LocationMatch>

 


More Setting

 

Body(Request)

# Configures whether request bodies will be buffered and processed by ModSecurity(POST data)

SecRequestBodyAccess On

# 當 POST 的 size 超過 SecRequestBodyLimit 時如何處理

SecRequestBodyLimitAction Reject

# Configures the maximum request body size that ModSecurity will store in memory.
# When a multipart/form-data request is being processed, once the in-memory limit is reached,
# the request body will start to be streamed into a temporary file on disk.

SecRequestBodyInMemoryLimit 131072

# file uploads. "413 Request Entity Too Large error"

SecRequestBodyLimit 15728640

# limits the size of POST data (不是 upload file 的 data)

SecRequestBodyNoFilesLimit 131072

# Enable XML request body parser.
# Initiate XML Processor in case of xml content-type

SecRule REQUEST_HEADERS:Content-Type "(?:application(?:/soap\+|/)|text/)xml" \
     "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"

# Enable JSON request body parser.
# Initiate JSON Processor in case of JSON content-type; change accordingly
# if your application does not use 'application/json'
#

SecRule REQUEST_HEADERS:Content-Type "application/json" \
     "id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON"

# As a rule of thumb, when failing to process a request body
# you should reject the request (when deployed in blocking mode)
# or log a high-severity alert (when deployed in detection-only mode).

SecRule REQBODY_ERROR "!@eq 0" \
"id:'200002', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2"

File uploads

The location where ModSecurity stores intercepted uploaded files

SecUploadDir /opt/modsecurity/var/upload

# allow group access the file

SecUploadFileMode 0660

# By default, only keep the files that were determined to be unusual in some way

#SecUploadKeepFiles RelevantOnly

Body(Response)

SecResponseBodyAccess Off

PCRE library

# Sets the match limit in the PCRE library.

SecPcreMatchLimit 1000

SecPcreMatchLimitRecursion 1000

Debug

log location

SecDebugLog /var/log/httpd/modsec_debug.log

log level

# 1–3 are always copied to the Apache error log.
# 4: details of how transactions are handled

SecDebugLogLevel 0

AuditLog

SecAuditEngine

# On / Off / RelevantOnly
# For every transaction that’s blocked, ModSecurity provides detailed logs about the transaction and why it was blocked.
# RelevantOnly: only the log transactions that have triggered a warning or an error
#                      or have a status code that matches what’s in the SecAuditLogRelevantStatus directive.

SecAuditEngine RelevantOnly

SecAuditLogRelevantStatus

# Configures which response status code is to be considered relevant for the purpose of audit logging.

# Must have SecAuditEngine set to RelevantOnly.

# The example provided would log all 5xx and 4xx level status codes, except for 404s.

SecAuditLogRelevantStatus "^(?:5|4(?!04))"

SecAuditLogType

# Serial: Audit log entries will be stored in a single file
# Concurrent: One file per transaction is used for audit logging

SecAuditLogType Serial

SecAuditLogParts

# Defines which parts of each transaction are going to be recorded in the audit log

SecAuditLogParts AHZ
  • A    Audit log header (mandatory)
  • B    Request headers
  • C    Request body
  • D    Reserved
  • E    Response body
  • F    Response headers
  • G    Reserved
  • H    Audit log trailer, which contains additional data # 中了那 Rule
  • I     Compact request body alternative (to part C), which excludes files
  • J     Information on uploaded files
  • K    Contains a list of all rules that matched for the transaction
  • Z    Final boundary (mandatory)

Audit log file location

SecAuditLog /var/log/httpd/modsec_audit.log

Miscellaneous

# The location specified needs to be writable by the Apache user process.
# for stores temporary files

SecTmpDir /var/lib/mod_security

# Path where persistent data (e.g., IP address data, session data, and so on)

SecDataDir /var/lib/mod_security

# character to use as the separator for application/x-www-form- urlencoded content.

SecArgumentSeparator &

 


mod_unique_id

 

UNIQUE_ID is set to the identifier for each request.

This module provides a magic token for each request which is guaranteed to be unique across "all" requests under very specific conditions.

The UNIQUE_ID environment variable is constructed by

encoding the 144-bit (32-bit IP address, 32 bit pid, 32 bit time stamp, 16 bit counter, 32 bit thread index)

quadruple using the alphabet [A-Za-z0-9@-] in a manner similar to MIME base64 encoding, producing 24 characters.

 


Install Core ModSecurity Rule Set ver.2.2.9

 

Core Rule Set (CRS)

License: ASLv2

https://github.com/coreruleset/coreruleset

A set of generic attack detection rules for use with ModSecurity

Prepare

mkdir /usr/src/coreruleset; cd /usr/src/coreruleset

wget https://github.com/coreruleset/coreruleset/archive/refs/tags/v3.3.2.zip

unzip v3.3.2.zip

cd coreruleset-3.3.2

Install

由於 /etc/httpd/conf.d/mod_security.conf 有以下設定

<IfModule mod_security2.c>
    # ModSecurity Core Rules Set configuration
        Include modsecurity.d/*.conf
        Include modsecurity.d/activated_rules/*.conf

所以我們 copy 相應的 file 到指定目錄即可

cp modsecurity_crs_10_setup.conf.example /etc/httpd/modsecurity.d/modsecurity_crs_10_setup.conf

for f in `ls base_rules/` ; do cp base_rules/$f /etc/httpd/modsecurity.d/activated_rules/$f ; done

apache error log

... [notice] ModSecurity for Apache/2.7.3 (http://www.modsecurity.org/) configured.
... [notice] ModSecurity: APR compiled version="1.3.9"; loaded version="1.3.9"
... [notice] ModSecurity: PCRE compiled version="7.8 "; loaded version="7.8 2008-09-05"
... [notice] ModSecurity: LUA compiled version="Lua 5.1"
... [notice] ModSecurity: LIBXML compiled version="2.7.6"

Default Setting

SecRuleEngine On

# - To log to both the Apache error_log and ModSecurity audit_log file use: "log"
# - To log *only* to the ModSecurity audit_log file use: "nolog,auditlog"
# - To log *only* to the Apache error_log file use: "log,noauditlog"

SecDefaultAction "phase:1,deny,log"
SecDefaultAction "phase:2,deny,log"

The 49 inbound blocking and 59 outbound blocking rules files use the "block" action

For test

SecDefaultAction "phase:1,pass"
SecDefaultAction "phase:2,pass"

測試

/home/vhosts/MYDOMAIN/web/test.php

<?php
  $content = file_get_contents($_GET['path']);
  echo nl2br($content);
?>

http://MYDOMAIN/test.php?path=../../../../etc/passwd

Log

# 960017

[Thu Sep 17 16:36:32 2015] [error] [client 192.168.88.177] ModSecurity: Access denied with code 403 (phase 2). Pattern match "^[\\\\d.:]+$" at REQUEST_HEADERS:Host. [file "/etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_21_protocol_anomalies.conf"] [line "98"] [id "960017"] [rev "2"] [msg "Host header is a numeric IP address"] [data "192.168.88.183"] [severity "WARNING"] [ver "OWASP_CRS/2.2.9"] [maturity "9"] [accuracy "9"] [tag "OWASP_CRS/PROTOCOL_VIOLATION/IP_HOST"] [tag "WASCTC/WASC-21"] [tag "OWASP_TOP_10/A7"] [tag "PCI/6.5.10"] [tag "http://technet.microsoft.com/en-us/magazine/2005.01.hackerbasher.aspx"] [hostname "192.168.88.183"] [uri "/test.php"] [unique_id "Vfp7kMCoWLcAAAYuBhQAAAAD"]

# 960024

[Thu Sep 17 16:44:19 2015] [error] [client 192.168.88.177] ModSecurity: Access denied with code 403 (phase 2). Pattern match "\\\\W{4,}" at ARGS:path. [file "/etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_40_generic_attacks.conf"] [line "37"] [id "960024"] [rev "2"] [msg "Meta-Character Anomaly Detection Alert - Repetative Non-Word Characters"] [data "Matched Data: ../../../../ found within ARGS:path: ../../../../etc/passwd"] [ver "OWASP_CRS/2.2.9"] [maturity "9"] [accuracy "8"] [hostname "test.loc"] [uri "/"] [unique_id "Vfp9Y8CoWLcAAAZMA5gAAAAH"]

 


多個 Vhosts Settings

 

SecWebAppId    # Default: default

Creates an application namespace, allowing for separate persistent session and user storage.
If it isn’t used, a collision between session IDs might occur.

<VirtualHost *:80>
  ServerName app1.example.com
  SecWebAppId "App1" ...
</virtualhost>

<VirtualHost *:80>
  ServerName app2.example.com
  SecWebAppId "App2" ...
</virtualhost>

 


SecConnEngine

 

"SecConnEngine" directive affect the directives: SecConnReadStateLimit and SecConnWriteStateLimit.

Apache to switches state to SERVER_BUSY_WRITE once request headers have been read.

As an alternative, consider mod_reqtimeout

SecReadStateLimit / SecConnReadStateLimit

Establishes a per-IP address limit of how many connections are allowed to be in SERVER_BUSY_READ state.

SecConnReadStateLimit 50 "!@ipMatch 127.0.0.1"

SecWriteStateLimit / SecConnWriteStateLimit

Establishes a per-IP address limit of how many connections are allowed to be in SERVER_BUSY_WRITE state.

SecConnWriteStateLimit 50 "!@ipMatch 127.0.0.1"

 


SecRemoteRules

 

Load rules from a given file hosted on a HTTPS site.

i.e.

SecRemoteRules some-key https://www.yourserver.com/plain-text-rules.txt

SecRemoteRulesFailAction Abort|Warn    # Default: Abort

Action that will be taken if SecRemoteRules specify an URL that ModSecurity was not able to download.

 


Doc

 

https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual

https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-(v2.x)-(Split)

 

 

Creative Commons license icon Creative Commons license icon