CONTACT
お問い合わせ

Apache Mod Security で基本的なセキュリティ設定を行う

ApacheのMod Securityを使用しリクエストサイズ制限やサーバ情報削除設定など基本的なセキュリティ対策を行う

目次

1.概要
2.構成図
3.前提
4.Mod Securityインストール
5.Apache設定
6.Mod Security設定ファイル編集
7.Mod Security設定適用
8.設定確認

1.概要

ApacheのMod Securityを使用し、設定ファイルの設定にてリクエストサイズ制限やサーバ情報削除設定などの基本的なセキュリティ対策を行う。

2.構成図

構成図は以下の通り。

OS CentOS 7
Apache 2.4.46
apr 1.6.5
apr-util 1.6.1
mod security 2.9.3

3.前提

・OSがCentOSであること
・Apacheがインストールされていること
・aprがインストールされていること
・apr-utilがインストールされていること
・Apache、Tomcatが稼働している場合は停止していること

4.Mod Securityインストール

Githubよりソースコードを取得(今回はmodsecurity-2.9.3.tar.gz)
  ◎ Mod Security配布サイト(Github)

アップロードを行い、解凍する

[root@Server1 ~]# cd /usr/local/src ※アップロード先
[root@Server1 ~]# tar -xvf modsecurity-2.9.3.tar.gz

必要モジュールのインストール

[root@Server1 ~]# yum install libxml2-devel

インストール済Apacheのapxsコマンドのパスを確認する

[root@Server1 ~]# ll /usr/local/httpd-2.4.46/bin/apxs
-rwxr-xr-x 1 apache apache 23889  3月 25 22:02 /usr/local/httpd-2.4.46/bin/apxs

Mod Securityのビルド・デプロイ(各コマンド実行時にでエラーメッセージが出なければOK)
 ※–with-apxs:apxsコマンドのパス
 ※–with-apr:aprのインストールディレクトリ
 ※–with-apu:apr-utilのインストールディレクトリ
 ※「make test」コマンドは正常にmakeできているかのテストであり、時間がかかる為スキップしても良い。

[root@Server1 ~]# cd modsecurity-2.9.3
[root@Server1 ~]# ./configure --with-apxs=/usr/local/httpd-2.4.46/bin/apxs --with-apr=/usr/local/apr-1.6.5 --with-apu=/usr/local/apr-util-1.6.1
[root@Server1 ~]# make
[root@Server1 ~]# make test
[root@Server1 ~]# make install

デプロイされてることを確認

[root@Server1 ~]#  ll /usr/local/modsecurity
合計 0
drwxr-xr-x 2 root root 30  4月  8 12:38 bin
drwxr-xr-x 2 root root 30  4月  8 12:38 lib

ソースコードディレクトリ内にある「modsecurity.conf-recommended」ファイルをApacheのconfフォルダにコピーし、ファイル権限を他と合わせる

[root@Server1 ~]# cp -p /usr/local/src/modsecurity-2.9.3/modsecurity.conf-recommended /usr/local/apache/conf/extra/modsecurity.conf
[root@Server1 ~]# chmod 644 /usr/local/apache/conf/extra/modsecurity.conf

ソースコードディレクトリ内にある「unicode.mapping」ファイルをApacheのconfフォルダにコピーし、ファイル権限を他と合わせる

[root@Server1 ~]# cp -p /usr/local/src/modsecurity-2.9.3/unicode.mapping /usr/local/httpd-2.4.46/conf/extra/
[root@Server1 ~]# chmod 644 /usr/local/httpd-2.4.46/conf/extra/unicode.mapping

5.Apache設定

必要モジュールがApacheインストールディレクトリ内に存在するか確認

[root@Server1 ~]# ll /usr/local/httpd-2.4.46/modules/mod_unique_id.so
[root@Server1 ~]# ll /usr/local/httpd-2.4.46/modules/mod_security2.so

Apache設定ファイル「httpd.conf」を編集する

編集対象ファイル {Apacheインストールディレクトリ}/conf/httpd.conf

「httpd.conf」にモジュール読み込みの為の記載を追記
 ※対象モジュールの記載が存在する場合は、コメント「#」を解除し、正しいパスを記載する。

LoadModule unique_id_module modules/mod_unique_id.so
LoadModule security2_module modules/mod_security2.so

「httpd.conf」にMod Securityの設定ファイルのパスを記載

<IfModule security2_module>
 Include conf/extra/modsecurity.conf
</IfModule>
~略~
LoadModule headers_module modules/mod_headers.so
LoadModule unique_id_module modules/mod_unique_id.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
~略~
LoadModule security2_module modules/mod_security2.so
~略~
<IfModule security2_module>
    Include conf/extra/modsecurity.conf
</IfModule>

6.Mod Security設定ファイル編集

Mod Security設定ファイル「modsecurity.conf」を編集する

編集対象ファイル {Apacheインストールディレクトリ}/conf/extra/modsecurity.conf

<modsecurity.conf 設定プロパティ>

SecRequestBodyAccess On
リクエスト本文へのアクセスを有効にする
 On:リクエスト本文をバッファリングする
 Off:リクエスト本文をバッファリングしない
secrule request_headers: Content-Type;” application=”” json=”” br=””>”id:’200001′,phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON”
JSON形式のリクエストヘッダーを、現在のCロケールを使用して全ての文字を小文字に変換する。
 Id:ルールのID
 phase:ルールの実行タイミング
     1:Phase リクエストヘッダー
     2:Phase リクエストボディ
     3:Phase レスポンスヘッダー
     4:Phase レスポンスボディ
     5:Phase ロギング
 t:none:指定された以前の変換関数が無効になる
 t:lowercase:現在のCロケールを使用して、すべての文字を小文字に変換する
 pass:次のルール検証に進む
 nolog:ログ出力しない
 ctl:requestBodyProcessor = JSON:リクエストをJSONとして処理する
SecRequestBodyNoFilesLimit 1048576
最大ファイルサイズをbyte単位で設定(1MB)
SecRequestBodyLimitAction Reject
リクエストの本文の最大サイズを超過した場合、超過分のリクエスト本文を破棄
id:’200002′, phase:2,t:none,log,deny,status:400,msg:’Failed to parse request body.’,logdata:’%{reqbody_error_msg}’,severity:2
リクエスト本文の解析に使用されるプロセッサの値が「0(エラーなし)」でない場合、リクエストを拒否
“id:’200003′,phase:2,t:none,log,deny,status:400, \
msg:’Multipart request body failed strict validation: \
PE %{REQBODY_PROCESSOR_ERROR}, \
BQ %{MULTIPART_BOUNDARY_QUOTED}, \
BW %{MULTIPART_BOUNDARY_WHITESPACE}, \
DB %{MULTIPART_DATA_BEFORE}, \
DA %{MULTIPART_DATA_AFTER}, \
HF %{MULTIPART_HEADER_FOLDING}, \
LF %{MULTIPART_LF_LINE}, \
SM %{MULTIPART_MISSING_SEMICOLON}, \
IQ %{MULTIPART_INVALID_QUOTING}, \
IP %{MULTIPART_INVALID_PART}, \
IH %{MULTIPART_INVALID_HEADER_FOLDING}, \
FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'”
「multipart/form-data」形式のリクエストを検査する
 !@eq 0:エラーの場合
 ※@eq:0(エラーなし)、1(エラー)
 phase:ルールの実行タイミング
     1:Phase リクエストヘッダー
     2:Phase リクエストボディ
     3:Phase レスポンスヘッダー
     4:Phase レスポンスボディ
     5:Phase ロギング
 t:none:指定された以前の変換関数が無効になる
 log:ログ出力する
 deny:リクエストを拒否
 status:応答ステータスコードを指定
 msg:レスポンス本文
“id:’200004′,phase:2,t:none,log,deny,msg:’Multipart parser detected a possible unmatched boundary.'”
multipart / request-bodyの解析フェーズ中に、一致しない可能性を検知した場合にリクエストを拒否する。
 !@eq 0:エラーの場合
 ※@eq:0(エラーなし)、1(エラー)
 Id:ルールのID
 phase:ルールの実行タイミング
     1:Phase リクエストヘッダー
     2:Phase リクエストボディ
     3:Phase レスポンスヘッダー
     4:Phase レスポンスボディ
     5:Phase ロギング
 t:none:指定された以前の変換関数が無効になる
 log:ログ出力する
 deny:リクエストを拒否
 msg:レスポンス本文
SecPcreMatchLimitRecursion 1000
PCRE(正規表現ライブラリ)の正規表現の最大再帰数を指定する。
※PCREの最大マッチング数を制限することで、ReDoS(正規表現DOS)攻撃によりサーバ負荷がかからないようにする。
SecResponseBodyMimeType text/plain text/html text/xml
検査対象のMIMEタイプを指定する(text/plain、text/html、text/xmlを対象とする)
SecResponseBodyLimitAction ProcessPartial
リクエストの本文の最大サイズを超過した場合、超過分のリクエスト本文は検査せず通過させる。
 Reject:破棄する
 ProcessPartial:SecRequestBodyLimit で指定したサイズまで検証し、残りはパスさせる
SecDataDir /usr/local/apache/logs/mod_security_data/
永続データ(IPアドレスデータ、セッションデータなど)が保存されるディレクトリ
SecUploadKeepFiles RelevantOnly
トランザクションの処理後に、傍受されたファイルを保持するかどうかを構成。
 On-アップロードしたファイルを保持する
 Off-アップロードされたファイルを保持しない
 RelevantOnly-これは、関連すると見なされるリクエストに属するファイルのみを保持する
SecDebugLog /usr/local/apache/logs/mod_security_debug.log
ModSecurityデバッグログファイルへのパス
SecAuditEngine RelevantOnly
監査ログを出力
 On:すべてのトランザクションをログに記録する
 Off:トランザクションをログに記録しない
 RelevantOnly:警告またはエラーをトリガーした、または関連すると見なされるステータスコードを持つログトランザクションのみ
SecAuditLogRelevantStatus “^(?:5|4(?!04))”
指定された正規表現に一致するステータスコードを持つトランザクションのみの監査ログを構成できるようにする
※404を除くすべての5xxおよび4xxレベルのステータスコードがログに記録される
SecAuditLogType Serial
使用する監査ログメカニズムのタイプを定義する
 Serial:SecAuditLogで指定された単一のファイルに保存される
 Concurrent:トランザクションごとに1つのファイルが監査ログに使用される
SecAuditLogStorageDir /usr/local/apache/logs/mod_security_audit/
同時監査ログエントリが保存されるディレクトリを定義
SecCookieFormat 0
アプリケーションのcookieタイプを指定
 0:バージョン0(Netscape)のCookieを使用。(ほとんどのアプリケーションがこちらを使用)
 1:バージョン1のCookieを使用。
SecStatusEngine Off
Webサーバーの起動時にステータスレポートをModSecurityプロジェクトチームに送信しない
 On:送信する
 Off:送信しない
SecServerSignature ” “
レスポンスデータにサーバ情報を載せない
SecRuleEngine On
SecRequestBodyAccess On
#SecRule REQUEST_HEADERS:Content-Type "(?:application(?:/soap\+|/)|text/)xml" \
#     "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"

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

SecRequestBodyLimit 2097152
SecRequestBodyNoFilesLimit 1048576
SecRequestBodyInMemoryLimit 1572864
SecRequestBodyLimitAction Reject

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"

#SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
#"id:'200003',phase:2,t:none,log,deny,status:400, \
#msg:'Multipart request body failed strict validation: \
#PE %{REQBODY_PROCESSOR_ERROR}, \
#BQ %{MULTIPART_BOUNDARY_QUOTED}, \
#BW %{MULTIPART_BOUNDARY_WHITESPACE}, \
#DB %{MULTIPART_DATA_BEFORE}, \
#DA %{MULTIPART_DATA_AFTER}, \
#HF %{MULTIPART_HEADER_FOLDING}, \
#LF %{MULTIPART_LF_LINE}, \
#SM %{MULTIPART_MISSING_SEMICOLON}, \
#IQ %{MULTIPART_INVALID_QUOTING}, \
#IP %{MULTIPART_INVALID_PART}, \
#IH %{MULTIPART_INVALID_HEADER_FOLDING}, \
#FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'"

#SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \
#"id:'200004',phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'"

#SecPcreMatchLimit 1000
#SecPcreMatchLimitRecursion 1000
#SecRule TX:/^MSC_/ "!@streq 0" \
#        "id:'200005',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'"
SecResponseBodyAccess Off
#SecResponseBodyMimeType text/plain text/html text/xml
#SecResponseBodyLimit 524288
#SecResponseBodyLimitAction ProcessPartial
SecTmpDir /usr/local/apache/logs/mod_security_tmp/
SecDataDir /usr/local/apache/logs/mod_security_data/
#SecUploadDir /opt/modsecurity/var/upload/
#SecUploadKeepFiles RelevantOnly
#SecUploadFileMode 0600
#SecDebugLog /usr/local/apache/logs/mod_security_debug.log
#SecDebugLogLevel 3
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogParts ABIJDEFHZ
SecAuditLogType Serial
SecAuditLog /usr/local/apache/logs/modsec_audit.log
#SecAuditLogStorageDir /usr/local/apache/logs/mod_security_audit/
SecArgumentSeparator &
SecCookieFormat 0
#SecUnicodeMapFile unicode.mapping 20127
SecStatusEngine Off
SecServerSignature " "

7.Mod Security設定適用

Apache・Tomcatを起動

[root@Server1 ~]# /usr/local/tomcat/bin/shutdown.sh
[root@Server1 ~]# /usr/local/tomcat/bin/startup.sh
[root@Server1 ~]# /usr/local/src/modsecurity-2.9.3/bin/apachectl start

8.設定確認

Mod Securityを設定したサーバへ、別サーバから設定値を超過サイズのリクエストを送り、200以外のHTTPステータスが返却されることを確認する。

[root@Server2 ~]# cd /usr/local/apache/bin/
[root@Server2 ~]# ./ab -n 1 -c 1 -p modsecurityTest1.xlsx -T 'application/x-www-form-urlencoded' http://{Server1のIPアドレス}:80/
This is ApacheBench, Version 2.3 <$Revision: 1879490 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 192.168.x.xx (be patient).....done


Server Software:
Server Hostname:        192.168.x.xx
Server Port:            80

Document Path:          /
Document Length:        316 bytes

Concurrency Level:      1
Time taken for tests:   0.083 seconds
Complete requests:      1
Failed requests:        0
Non-2xx responses:      1
Total transferred:      490 bytes
Total body sent:        2171919
HTML transferred:       316 bytes
Requests per second:    12.09 [#/sec] (mean)
Time per request:       82.682 [ms] (mean)
Time per request:       82.682 [ms] (mean, across all concurrent requests)
Transfer rate:          5.79 [Kbytes/sec] received
                        25652.68 kb/s sent
                        25658.46 kb/s total

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        1    1   0.0      1       1
Processing:    82   82   0.0     82      82
Waiting:        0    0   0.0      0       0
Total:         83   83   0.0     83      83

ModSecurityを設定したサーバのApacheログ「access_log」「error_log」にエラーログが出力されていること、HTTPエラーコードが返されていることを確認する。

確認ログ① {Apacheインストールディレクトリ}/logs/access_log
192.168.x.xx - - [28/May/2021:14:46:04 +0900] "POST / HTTP/1.0" 413 316
確認ログ② {Apacheインストールディレクトリ}/logs/error_log
[Fri May 28 14:46:04.571377 2021] [:error] [pid 13759:tid 140379139933952] [client 192.168.x.xx:57218] [client 192.168.x.xx] ModSecurity: Request body (Content-Length) is larger than the configured limit (2097152). [hostname "192.168.x.xx"] [uri "/"] [unique_id "YLCDnKZKK42niMO9p472ugAAAcI"]