WAF★ModSecurity構築

2021年1月20日

WAF(Web Application Firewall)には沢山の種類があります。今回はそのうちの一つModSecurityをインストールして簡単な設定まで行いたいと思います。

ModSecurityの特徴

WAFには色んな種類がありますが、ModSecurityには次のような特徴があります。

シグネチャ型のWAF

シグネチャ型とは不正なアクセス・許可するアクセスを予め登録してそれを元に検知する、という意味です。ModSecurityでは不正なアクセスと見なせるルールを作成してそのルールに合致すれば検知してアクセス拒否等の処理を施してくれます。その為、不正なアクセスの情報を更新することが必要になってきます。

そこでOWASPファウンデーションで作成してくれているOWASP ModSecurity Core Rule Set (CRS)をシグネチャとして利用することにより、簡単にModSecurityを使用することが出来ます。このCRSは時々更新されているようなので定期的に確認しましょう。

ModSecurityのインストール

まずはModSecurityをインストールします。yumでサクッと完成します。

インストール環境

  • CentOS 7.7
  • httpd(apache) 2.4.41

インストール作業

ModSecurityをyumでインストールします。

yum install -y mod_security mod_security_crs
  • mod_security・・・・・ModSecurity本体(apacheモジュール)
  • mod_security_crs・・・CRSルールファイル

ModSecurityの準備作業

ModSecurityの準備を行います。起動させる前に確認しておきましょう。

ModSecurity設定の為の準備

各種ファイルの場所

Modsecurity関連ファイルの場所は次の通りです。

  • /etc/httpd/conf.d/mod_security.conf
    (メインの設定ファイル)
  • /etc/httpd/modsecurity.d/
    (検出ルールファイルディレクトリ)
  • /etc/httpd/modsecurity.d/activated_rules/
    (/usr/lib/modsecurity.d/にあるCRSルールファイルのシンボリックリンク配置ディレクトリ)
  • /usr/lib/modsecurity.d/base_rules/
    (CRSルールファイルディレクトリ)

CRSルールの適用は/etc/httpd/modsecurity.d/activated_rules/ディレクトリに/usr/lib/modsecurity.d/ディレクトリにあるCRSルール(conf)ファイルのシンボリックリンクを貼ることで有効になります。

CRSルールファイル(シンボリックリンク)のバックアップ

シンボリックリンクは後から自分でも作れるのでバックアップを取る程でもないんですが、念のため取っておきます。

/etc/httpd/modsecurity.d/activated_rules/にあるルールファイルのシンボリックリンクのバックアップを取得します。次のコマンドで行います。

cp -rp activated_rules activated_rules.bk

コマンド解説

cp -rp コピー元ディレクトリ名 コピー先ディレクトリ名

ディレクトリ(又はファイル)のコピーを行います。

-rディレクトリ毎コピー。サブディレクトリも含む。
-pパーミッションと所有者とタイムスタンプを保持する

ログの設定

ログファイルの場所

ログファイルの場所は次の通りです。

  • /var/log/httpd/modsec_audit.log

ログを取得する場合

ログはデフォルトで取得する設定になっていますが念のため確認しておきましょう。

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

ログを取得するとログが肥大化する恐れがあります。それを防ぐ為にローテーションの設定をしておきます。/etc/logrotate.d/ディレクトリにmod_securityの名前(名前は任意)でログをローテーションさせる設定ファイルを作成しましょう。

# /etc/logrotate.d/mod_security
/var/log/httpd/modsec_audit.log {
    daily
    rotate 7
    missingok
    compress
    postrotate
        /sbin/service httpd reload > /dev/null 2>/dev/null || true
    endscript
}

後は設定を反映させます。

logrotate -v /etc/logrotate.conf

ログのローテーションに関する詳しい内容はこちら。

ログを取得しない場合

ログが必要ない時は取得しない設定にしましょう。ログファイルmodsec_audit.logはすぐに肥大化するらしいので無効にしておきます。設定するファイルと内容は次の通りです。

vi /etc/httpd/conf.d/mod_security.conf
# SecAuditEngine RelevantOnly→Off
SecAuditEngine Off

シグネチャのアップデート

シグネチャは半年に一回程度アップデートされるらしいので、定期的に確認するようにしましょう。yumコマンドでインストールしているのでyumのアップデートで対応できると思います。

ModSecurityの設定

ModSecurityの設定を行います。デフォルトのままでも利用は可能ですが、やや厳格にルールが設定されている為修正した方がいいでしょう。

ModSecurityの設定方法は3つ

大雑把に分けてModSecurityの設定方法は次の三つです。

  • mod_security.conf内で設定
    (システム全体に大まかな項目を適用)
  • ルールファイルで設定
    (システム全体に対し詳細を設定)
  • 各サービスのconfファイルで設定
    (各サービスに対し詳細を設定)

それぞれ適用範囲・内容によって設定する箇所を分けましょう。設定後はapacheを再起動。

ModSecurity基本的なルールの設定

ModSecurityの基本的な設定はCRSルールファイルのシンボリックリンクを選択することです。

  • /etc/httpd/modsecurity.d/activated_rules/

この中にあるシンボリックリンクを必要な物だけ残し不要な物は削除します。

おそらく重要となるルールファイルは次の二つです。

  • modsecurity_crs_41_sql_injection_attacks.conf
  • modsecurity_crs_41_xss_attacks.conf

まずはこの二つを適用し、あとは適宜監視しながら検討しましょう。

ModSecurityの動作確認

apache(httpd)のテスト

ModSecurityの動作確認をapacheで行います。

(準備作業)IPアドレスでのアクセスを許可

念のため、IPアドレスでアクセス可能に設定しておきます。ルールID960017はIPアドレスでのアクセスに警告を出すので無効にする処理を行います。

httpd.confのホームディレクトリに次の内容を記載しましょう。

<Directory "/home/www/html">
    # mod_security(CRS)
    SecRuleRemoveById 960017
</Directory>

“SecRuleRemoveById 960017" でルールID960017を無効化しています。修正したらhttpdを再起動しましょう。

systemctl restart httpd

不正なアクセスのテスト

次に下記の通りにブラウザからアクセスしてください。

http://サーバのIPアドレス?union+select

ブラウザの画面には"Forbidden"と表示されているはずです。ログには次のような内容が記載されています。

vi /var/log/httpd/modsec_audit.log

–43e9c826-A–
[12/Apr/2020:13:16:02 +0900] XpKWAhEGsMrW0lt9Q@-9bgAAAAA 192.168.33.1 54875 192.168.33.13 80
–43e9c826-B–
GET /test.html?union+select HTTP/1.1
Host: 192.168.33.13
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8
Accept-Language: ja,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
–43e9c826-F–
HTTP/1.1 403 Forbidden
Content-Length: 199
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=iso-8859-1
–43e9c826-E–
–43e9c826-H–
Message: Access denied with code 403 (phase 2). Pattern match “(?i:\b(?:(?:s(?:t(?:d(?:dev(pop|_samp)?)?|r(?:_to_date|cmp))|u(?:b(?:str(?:ing(_index)?)?|(?:dat|tim)e)|m)|e(?:c(?:_to_time|ond)|ssion_user)|ys(?:tem_user|date)|ha(1|2)?|oundex|chema|ig?n|pace|qrt)|i(?:s(null|(free_lock|ipv4_compat|ipv4_mapped|ipv4| …" at ARGS_NAMES:union select. [file “/etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_41_sql_injection_attacks.conf"] [line “125"] [id “950001"] [rev “2"] [msg “SQL Injection Attack"] [data “Matched Data: union select found within ARGS_NAMES:union select: union select"] [severity “CRITICAL"] [ver “OWASP_CRS/2.2.9"] [maturity “9"] [accuracy “8"] [tag “OWASP_CRS/WEB_ATTACK/SQL_INJECTION"] [tag “WASCTC/WASC-19"] [tag “OWASP_TOP_10/A1"] [tag “OWASP_AppSensor/CIE1"] [tag “PCI/6.5.2"]
Apache-Error: [file “apache2_util.c"] [line 271] [level 3] [client 192.168.33.1] ModSecurity: Access denied with code 403 (phase 2). Pattern match “(?i:\\\\b(?:(?:s(?:t(?:d(?:dev(pop|_samp)?)?|r(?:_to_date|cmp))|u(?:b(?:str(?:ing(_index)?)?|(?:dat|tim)e)|m)|e(?:c(?:_to_time|ond)|ssion_user)|ys(?:tem_user|date)|ha(1|2)?|oundex|chema|ig?n|pace|qrt)|i(?:s(null|(free_lock|ipv4_compat|ipv4_mapped|ipv4| …" at ARGS_NAMES:union select. [file “/etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_41_sql_injection_attacks.conf"] [line “125"] [id “950001"] [rev “2"] [msg “SQL Injection Attack"] [data “Matched Data: union select found within ARGS_NAMES:union select: union select"] [severity “CRITICAL"] [ver “OWASP_CRS/2.2.9"] [maturity “9"] [accuracy “8"] [tag “OWASP_CRS/WEB_ATTACK/SQL_INJECTION"] [tag “WASCTC/WASC-19"] [tag “OWASP_TOP_10/A1"] [tag “OWASP_AppSensor/CIE1"] [tag “PCI/6.5.2"] [hostname “192.168.33.13"] [uri “/test.html"] [unique_id “XpKWAhEGsMrW0lt9Q@-9bgAAAAA"]
Action: Intercepted (phase 2)
Stopwatch: 1586664962532436 2341 (- – -)
Stopwatch2: 1586664962532436 2341; combined=1132, p1=378, p2=685, p3=0, p4=0, p5=69, sr=60, sw=0, l=0, gc=0
Response-Body-Transformed: Dechunked
Producer: ModSecurity for Apache/2.9.2 (http://www.modsecurity.org/); OWASP_CRS/2.2.9.
Server: Apache/2.4.41 (IUS) OpenSSL/1.0.2k-fips
Engine-Mode: “ENABLED"
–43e9c826-Z–

大量の記載がありますがログの重要なポイントは"–H–“の項目だけです。その中のメッセージを見てみると

  • Message: Access denied with code 403 (phase 2).
  • msg “SQL Injection Attack"

と記載がされています。正しく動作しているようです。

偽陽性テスト

運用テストを行うためには一定期間、自分自身でルールが正しく適用されているか確認する必要があります。

一定期間観察する為、ModSecurityの設定を検知のみにしておきましょう。設定は次の通りです。

vi /etc/httpd/conf.d/mod_security.conf
# SecRuleEngine On → DetectionOnly
SecRuleEngine DetectionOnly

この状態でログを確認して正しく動作しているか経過観察してみましょう。

WAFModSecurity

Posted by Bright_Noah