mod_security#

last update 2024/03/04

summary#

GoAccess is an open source real-time web log analyzer.

前提条件#

prerequisite#

OS

Apache

AlmaLinux 9

2.4.57

Install#

dnf -y install mod_security mod_security_crs
modules#

module

Feature

mod_security

WAF

mod_security_crs

ルールセット

コンフィグ設定#

機能の有効・無効#

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

Property

Feature

Value

SecRuleEngine

WAFの有効無効

On=有効

Off=無効

SecRequestBodyAccess

リクエスト本文へのアクセスの有効無効

On=リクエスト本文のバッファリングを有効

Off=リクエスト本文のバッファリングを無効

検知ルール#

選択した演算子を使用して選択した変数を分析するルールを作成する

構文#

SecRule#

注釈

選択された演算子を使用して選択された変数を分析するルールの作成
演算子を提供しない場合、デフォルトのリストが使用される
SecRule VARIABLES OPERATOR [ACTIONS]
SecRule ARGS "@rx attack" "phase:1,log,deny,id:1"
format#

Parameter

Notes

VARIABLES

下記変数を指定

OPERATOR

@<OPERATOR> と書く OPERATORを省略すると正規表現マッチ(@rx)と見なされる

ACTIONS

条件にマッチした場合に実行する処理 省略した場合は**SecDefaultAction**が適用される

SecAction#

注釈

アクションリストを無条件に処理する。
パラメタの構文はSecRuleの第3パラメタと同じ。
SecAction "action1,action2,action3"
SecAction nolog,phase:1,initcol:RESOURCE=%{REQUEST_FILENAME}
format#

Parameter

Notes

ACTIONS

アクション1,アクション2...

SecDefaultAction#

注釈

特定のフェーズのアクションのデフォルトリストを定義する。
SecDefaultAction "action1,action2,action3"
SecDataDir#

注釈

IPアドレスデータ、セッションデータ等を保存するパス
initcol, setsid, setuid を使う前に指定
Webサーバのユーザが書き込み可能なディレクトリを指定
VirtualHosts内は使用不可
SecDataDir /path/to/dir
SecDataDir /usr/local/apache/logs/data
SecResponseBodyAccess#

注釈

レスポンスボディをバッファするかどうかの設定
SecResponseBodyMimeTypeに設定したMIMEタイプにマッチする場合のみ
SecResponseBodyAccess On|Off
SecResponseBodyMimeType#

注釈

レスポンスボディをバッファするMIMEタイプの設定
SecResponseBodyMimeType MIMETYPE MIMETYPE ...
# example
SecResponseBodyMimeType text/plain text/html text/xml
# default
text/plain text/html

変数 (VARIABLES)#

リクエスト#
request#

Variable

Collection

REQUEST_COOKIES

リクエストクッキー(値のみ)

REQUEST_COOKIES_NAMES

リクエストクッキーの名前

REQUEST_FILENAME

クエリ文字列部分を除いた相対リクエストURLを保持

REQUEST_METHOD

トランザクションで仕様されるリクエストメソッドを保持

REQUEST_PROTOCOL

リクエストプロトコルバージョン情報を保持

REQUEST_LINE

リクエストメソッド・HTTPバージョン情報を含む行全体を保持

# REQUEST_COOKIES (Cookieヘッダが含まれていない場合にトリガされる例)
SecRule &REQUEST_COOKIES "@eq 0" "id:44"

# REQUEST_COOKIES_NAMES (JSESSIONIDクッキーが存在しない場合にトリガされる例)
SecRule &REQUEST_COOKIES_NAMES:JSESSIONID "@eq 0" "id:45"

# REQUEST_FILENAME
SecRule REQUEST_FILENAME "^/cgi-bin/login.php$" phase:2,id:46,t:none,t:normalizePath

# REQUEST_METHOD
SecRule REQUEST_METHOD "^(?:CONNECT|TRACE)$" "id:50,t:none"

# REQUEST_PROTOCOL
SecRule REQUEST_PROTOCOL "!^HTTP/(0.9|1.0|1.1)$" "id:51"

# REQUEST_LINE (POST/GET/HEADリクエストのみを許可する例)
SecRule REQUEST_LINE "!(^((:(:POS|GE)T|HEAD))|HTTP/(0.9|1.0|1.1)$)" "phase:1,id:49,log,block,t:none"
レスポンス#
responce#

Variable

Collection

RESPONSE_STATUS

HTTP応答コードを保持

RESPONSE_BODY

レスポンスボディのデータを保持(バッファリングが有効になっている場合のみ)

# RESPONSE_STATUS (4xx・5xxを拒否する例)
SecRule RESPONSE_STATUS "^[45]" "phase:3,id:58,t:none"

# RESPONSE_BODY
SecRule RESPONSE_BODY "ODBC Error Code" "phase:4,id:54,t:none"
リモート#
remote#

Variable

Collection

REMOTE_ADDR

クライアントのIPアドレスを保持

REMOTE_HOST

名前解決したリモートホスト名を保持(ApacheのHostnameLookupsがONの場合)

REMOTE_PORT

接続に使用したソースポートを保持

REMOTE_USER

認証ユーザ名を保持(Basic認証・Digest認証)

# REMOTE_ADDR
SecRule REMOTE_ADDR "@ipMatch 192.168.1.101" "id:35"

# REMOTE_HOST
SecRule REMOTE_HOST "\.evil.networkorg$" "id:36"

# REMOTE_PORT (1024より小さいかどうかを評価する例)
SecRule REMOTE_PORT "@lt 1024" "id:37"

# REMOTE_USER
SecRule REMOTE_USER "@streq admin" "id:38"
コレクション#
args#

Collection

Description

ARGS

静的パラメタ、正規表現を含む引数を指定

ARGS_GET

クエリ文字列パラメタのみ対象

ARGS_POST

POSTボディの引数のみ対象

ARGS_NAMES

すべてのリクエストパラメタ名を含む(感嘆符のついた反転ルールを使って引数を許可することも可能)

# ARGS (すべてのリクエスト引数を調べる例)
SecRule ARGS dirty "id:7"

# ARGS ([p] という名前の引数を指定する例 ARGS:<指定引数>)
SecRule ARGS:p dirty "id:8"

# ARGS ([p] という名前の引数を除外する例 ARGS|!ARGS:<指定引数>)
SecRule ARGS|!ARGS:p dirty "id:9"

# ARGS (引数の数をカウントする例=0以上の場合 $ARGS !^<数>$)
SecRule &ARGS !^0$ "id:10"

# ARGS ([id_] で始まる名前をもつすべての引数を指定する例(ARGS:/<引数>/)
SecRule ARGS:/^id_/ dirty "id:11"

# ARGS_NAMES ([p][a]の引数名を許可する例)
SecRule ARGS_NAMES "!^(p|a)$" "id:13"

id#

注釈

ルールまたはチェーンに一意のIDを割り当てる
id#

id ranges

Reserved

available

1–99999

local use

100000–399999

used

400000–419999

unused

420000–439999

used

440000-599999

unused

600000-4300999

used

4301000-19999999

unused

20000000-21999999

used

22000000-69999999

unused

77000000-99209999

used

t:none#

注釈

SecRuleの変換関数はSecDefaultActionの指定に追加される
SecDefaultActionによっては、SecRuleの設定が阻害されるため、SecDefaultActionの設定を無効化する

Action#

phase#
phase#

Command

Phase

Description

phase:1

リクエストヘッダ

リクエストヘッダを読み終わった直後に処理(ボディを読込む前)

phase:2

リクエストボディ

汎用入力分析フェーズ リクエストボディフェースのデータにアクセスするために SecRequestBodyAccessをOnに設定

phase:3

レスポンスヘッダ

レスポンスヘッダがクライアントに返される直前に処理

phase:4

レスポンスボディ

汎用出力分析フェーズ 送信されたHTMLの情報開示、エラーメッセージ、認証に失敗したテキストなどを検査 SecRequestBodyAccessをOnに設定

phase:5

ロギング

ロギングが実行される直前に実行 ログ収集されたエラーメッセージを検査 このフェーズでは接続を拒否・ブロックすることができない

accuracy (アクショングループ:メタデータ)#

注釈

陽性/陰性に関するルールの相対的な精度レベルを指定
値は数値スケール(1~9で、9は非常に強く、1は偽陽性が多い)
allow (アクショングループ:破壊的)#

注釈

一致に成功するとルール処理を停止し、トランザクションの続行を許可する
# 192.168.1.100 からのアクセスを許可
SecRule REMOTE_ADDR "^192.168.1.100$" phase:1,id:95,nolog,allow
pass (アクショングループ:破壊的)#

注釈

マッチしても次のルールで処理を続行する
SecRule REQUEST_HEADERS:User-Agent "Test" "log,pass,id:122"
block (アクショングループ:破壊的)#

注釈

SecDefaultActionで定義された破壊的アクションを実行する
# どのようにブロックするかを指定
SecDefaultAction phase:2,deny,id:101,status:403,log,auditlog

# ブロックする
SecRule ARGS attack1 phase:2,block,id:102
drop (アクショングループ:破壊的)#

注釈

FINパケットを送信することで、TCPコネクションの即時クローズを開始する
ブルートフォース攻撃とサービス拒否攻撃の両方に対応する場合に非常に便利
# Basic認証の試行を追跡=IP収拾の開始、クライアントが2分間に25回以上の試行を超えた場合dropする
SecAction phase:1,id:109,initcol:ip=%{REMOTE_ADDR},nolog
SecRule ARGS:login "!^$" "nolog,phase:1,id:110,setvar:ip.auth_attempt=+1,deprecatevar:ip.auth_attempt=25/120"
SecRule IP:AUTH_ATTEMPT "@gt 25" "log,drop,phase:1,id:111,msg:'Possible Brute Force Attack'"
append (アクショングループ:非破壊)#

注釈

パラメータとして与えられたテキストをレスポンスボディの最後に追加
phase:3 and 4
SecRule RESPONSE_CONTENT_TYPE "^text/html" "nolog,id:99,pass,append:'<hr>フッター'"
auditlog (アクショングループ:非破壊)#

注釈

監査ログに記録するトランザクションをマークする
logが既に指定されている場合、auditlogアクションは明示的になる
SecRule REMOTE_ADDR "^192\.168\.1\.100$" auditlog,phase:1,id:100,allow
log (アクショングループ:非破壊)#

注釈

一致したルールをApacheエラーログ・ModSecurity監査ログに記録する
SecAction phase:1,id:117,pass,initcol:ip=%{REMOTE_ADDR},log
nolog (アクショングループ:非破壊)#

注釈

一致したルールをログに記録しない
SecRule REQUEST_HEADERS:User-Agent "Test" allow,nolog,id:121
intcol (アクショングループ:非破壊)#

注釈

メモリ内に新しいコレクションを作成することで名前付き永続コレクションを初期化する
# IPアドレス追跡を開始
SecAction phase:1,id:116,nolog,pass,initcol:ip=%{REMOTE_ADDR}

設定パタン#

ホワイトリスト (IPアドレス)#

SecRule REMOTE_ADDR "@pmFromFile modsec-white-ip" "phase:1,id:400001,nolog,allow,ctl:ruleEngine=Off,ctl:auditEngine=Off"
/etc/httpd/conf.d/modsec-white-ip#
112.34.56.78
222.34.56.78
332.34.56.78

ブラックリスト (IPアドレス)#

SecRule REMOTE_ADDR "@pmFromFile modsec-black-ip" "phase:1,id:400002,drop,msg:'Blacklisted IP address'"
/etc/httpd/conf.d/modsec-lblack-ip#
112.34.56.78
222.34.56.78
332.34.56.78

ブラックリスト (URL文字列)#

SecRule REQUEST_URI "@pmFromFile modsec-black-uri" "phase:1,id:400003,drop,auditlog"
/etc/httpd/conf.d/modsec-lblack-ip#
1<拒否する文字列>
2<拒否する文字列>

DOS対策・ブルーとフォース対策#

# @streq 401 = HTTP応答コード401を検知
# setvar: = 変数を作成・削除・更新する (大文字・小文字を区別しない) ここでは ip.401_cnt に+1を加算
# deprecatevar: = 360秒(6分)毎に1減算する 360秒以内に1回以上のアクセスがあるかを検出
# expirevar: = 有効期限を秒数で指定 expirevar:ip.401_cnt=86400 などとする
# ip:401_cnt "@gt 1" = 変数が1以上の場合、リクエストボディ取得時にパケットを即時終了する
SecAction phase:1,id:410001,nolog,initcol:ip=%{REMOTE_ADDR}
SecRule RESPONSE_STATUS "@streq 401" "phase:5,id:410002,t:none,nolog,pass,setvar:ip.401_cnt=+1,deprecatevar:ip.401_cnt=1/360"
SecRule ip:401_cnt "@gt 1" "phase:2,id:410003,drop,auditlog,msg:'upper limit of 401 has been exceeded'"

# basic認証・digest認証のブルートフォースを検知
#
SecAction phase:1,id:410004,nolog,initcol:ip=%{REMOTE_ADDR}
SecRule ARGS:login "!^$" "nolog,phase:1,id:410005,setvar:ip.auth_attempt=+1,deprecatevar:ip.auth_attempt=25/120"
SecRule IP:AUTH_ATTEMPT "@gt 25" "auditlog,drop,phase:1,id:410006,msg:'Possible Brute Force Attack'"

監査ログ#

セパレータフォーマット#

--<ID>-<分類>--

分類#

audit_log#

文字

説明

A

監査ログヘッダ(必須)

B

リクエストヘッダ

C

リクエストボディ (リクエストボディが存在し、ModSecurityがそれを傍受するように 設定されている場合にのみ存在する。これにはSecRequestBodyAccessをonに設定する必要がある)

D

中間応答ヘッダーのために予約

E

中間レスポンスボディ(ModSecurity がレスポンスボディを傍受するように設定されており、監査ログエンジンがそれを記録するように設定されている場合にのみ存在する。レスポンスボディを傍受するには、SecResponseBodyAccess が有効になっている必要がある)。ModSecurity が中間レスポンスボディを傍受しない限り、中間レスポンスボディは実際のレスポンスボディと同じ

F

最終的なレスポンスヘッダ (Date と Server ヘッダを除く。これは Apache が常にコンテンツ配送の後期に追加)

G

実際のレスポンスボディのために予約

H

監査ログのトレイラー

I

この部分は ModSecurity v3 では未実装

J

このパートは、multipart/form-data エンコーディングを使ってアップロードされたファイルに関する情報を含む

K

この部分は ModSecurity v3 では未実装

Z

最終境界、エントリーの終わりを意味する(必須)