Apacheモジュール

Ubuntu20.04サーバにApacheのDoS対策モジュール(mod_evasive)を導入。

概要

DoS/DDoS対策ができるモジュールをApacheに導入したときのメモです。

環境

さっくりとした手順

  1. mod_evasiveモジュールをインストールします。
  2. apache2実行ユーザー(www-data)がufwを利用できるように設定します。
  3. mod_evasiveモジュールの設定をします。
  4. 設定の反映を行います。

まずはサーバにターミナルログインするところから始めます。

mod_evasiveのインストール

sudo aptitude install libapache2-mod-evasive

このとき、postfixが依存関係でインストールされる場合があります。メール機能が使えない(AWS等で送信が制限されているなど)は、途中の設定で「何もしない」を選択します。

apache2実行ユーザーの権限変更

これは、www-dataがufwを実行する場合の処理です。権限昇格の危険性を承知した上で、慎重に作業を行ってください。

sudo cp -pi /etc/sudoers /path/to/backup/directory/sudoers.$(date +%Y%m%d)

任意のバックアップディレクトリを指定します。

sudo diff -u /path/to/backup/directory/sudoers.$(date +%Y%m%d) /etc/sudoers

差分がないことを確認します。

echo 'www-data ALL=(ALL) NOPASSWD: /usr/sbin/ufw' | sudo tee -a /etc/sudoers
sudo diff -u /path/to/backup/directory/sudoers.$(date +%Y%m%d) /etc/sudoers

以下の差分を確認します。

+www-data ALL=(ALL) NOPASSWD: /usr/sbin/ufw

evasiveの設定変更

sudo cp -pi /etc/apache2/mods-available/evasive.conf /path/to/backup/directory/evasive.conf.$(date +%Y%m%d)
sudo diff -u /path/to/backup/directory/evasive.conf.$(date +%Y%m%d) /etc/apache2/mods-available/evasive.conf

差分がないことを確認します。

    DOSHashTableSize    3097
    DOSPageCount        100
    DOSSiteCount        100
    #かなり緩く設定して、後で狭めていった方が偽陽性を防げます。
    DOSPageInterval     1
    DOSSiteInterval     1
    DOSBlockingPeriod   10

    #DOSEmailNotify      you@yourdomain.com
    #メール通知を行わないため、ここを省いています
    DOSSystemCommand    "sudo ufw deny proto tcp from %s to any port 80,443"
    # 検証時に自分のサイトがブロックされるのを防ぐため、ポートは80/443に絞っています
    DOSLogDir           "/var/log/mod_evasive"
    DOSWhitelist        127.0.0.1
    DOSWhitelist        xx.xx.xx.xx
    # 対象外としたいIPアドレス(自分の環境など)

参考:Apache の DoS攻撃対策モジュール mod_evasive

sudo diff -u /path/to/backup/directory/evasive.conf.$(date +%Y%m%d) /etc/apache2/mods-available/evasive.conf
-    #DOSHashTableSize    3097
-    #DOSPageCount        2
-    #DOSSiteCount        50
-    #DOSPageInterval     1
-    #DOSSiteInterval     1
-    #DOSBlockingPeriod   10
+    DOSHashTableSize    3097
+    DOSPageCount        100
+    DOSSiteCount        100
+    DOSPageInterval     1
+    DOSSiteInterval     1
+    DOSBlockingPeriod   10
 
     #DOSEmailNotify      you@yourdomain.com
-    #DOSSystemCommand    "su - someuser -c '/sbin/... %s ...'"
-    #DOSLogDir           "/var/log/mod_evasive"
+    DOSSystemCommand    "sudo ufw deny proto tcp from %s to any port 80,443"
+    DOSLogDir           "/var/log/mod_evasive"
+    DOSWhitelist        127.0.0.1
+    DOSWhitelist        xx.xx.xx.xx
 </IfModule>

設定反映

sudo apache2ctl configtest

Syntax OKを確認します。

sudo systemctl restart apache2.service

これで、不審なアクセスが大量にあったときにufwで弾く体制が整いました。

UbuntuサーバにMod_Securityを導入。

ApacheのWAFモジュールであるmod_securityを導入します。

として機能しているにもかかわらず文書化していなかったので、Web Arenaでの検証を機に文章に残します。

環境

※ パッケージ管理にaptitudeを用いています。必要に応じてaptに読み替えてください。

さっくりとした手順

  1. mod_securityのインストールを行います。
  2. mod_securityの設定を行います。
  3. Apacheのバーチャルサイトにmod_securityを組み込みます。
  4. 設定を反映して動作を確認します。

mod_securityのインストールを行います。

sudo aptitude update
sudo aptitude install libapache2-mod-security2
sudo apache2ctl -M |grep security
security2_module (shared)

と表示されていることを確認します。

ModSecurityの設定

sudo mv /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf

推奨ファイルをそのまま設定ファイルとして書き換えます。

OWASP Core Rule Set (CRS)のインストールと設定

cd /usr/share/modsecurity-crs && pwd
sudo git clone https://github.com/coreruleset/coreruleset.git
sudo mv /usr/share/modsecurity-crs/coreruleset/crs-setup.conf.example /usr/share/modsecurity-crs/coreruleset/crs-setup.conf

mod_securityモジュールにCRSを読み込む設定を追記

cd /etc/apache2/mods-available/ && pwd
sudo cp -pi security2.conf /path/to/backup/directory/security2.conf.$(date +%Y%m%d)

任意のバックアップディレクトリを指定します。

diff -u /path/to/backup/directory/security2.conf.$(date +%Y%m%d) security2.conf

エラーがなければバックアップは成功です。

/etc/apache2/mods-available/security2.confを、以下の差分になるように教義・信仰に沿ったエディタで編集します。(要root権限)

- </IfModule>
+        # Include OWASP ModSecurity CRS rules if installed
+        IncludeOptional /usr/share/modsecurity-crs/*.load
+</IfModule>
sudo apache2ctl configtest

Syntax OKを確認します。

sudo systemctl restart apache2.service
systemctl status apache2.service

active (running) を確認します。

Apacheのバーチャルサイト編集

稼働済みのApacheバーチャルサイトの設定ファイルをいじります。バックアップ確認は入念に行ってください。

cd /etc/apache2/sites-available && pwd
sudo cp -pi your_site.conf /path/to/backup/directory/your_site.conf.$(date +%Y%m%d)

.confファイルやバックアップディレクトリは自分の環境を指定します。

diff -u /path/to/backup/directory/your_site.conf.$(date +%Y%m%d) your_site.conf

エラーがなければバックアップは成功です。

/etc/apache2/sites-available/your_site.confを、以下の差分になるように教義・信仰に沿ったエディタで編集します。(要root権限)

# Mod Security

## ModSecurity有効化
SecRuleEngine On
## ModSecurity検知モード
### 検知モードで動かす場合はSecRuleEngine Onをコメントアウトしてこちらを有効化します
#SecRuleEngine DetectionOnly

## ファイルのアップロードをできるようにします。
SecRequestBodyInMemoryLimit 524288000
SecRequestBodyLimit 524288000

## テスト用の検知パラメータを付け加えます。
    SecRule ARGS:modsecparam "@contains test" "id:4321,deny,status:403,msg:'ModSecurity test rule has triggered'"
diff -u /path/to/backup/directory/your_site.conf.$(date +%Y%m%d) your_site.conf
+# Mod Security
+
+## ModSecurity有効化
+SecRuleEngine On
+## ModSecurity検知モード
+### 検知モードで動かす場合はSecRuleEngine Onをコメントアウトしてこちらを有効化します
+#SecRuleEngine DetectionOnly
+ 
+## ファイルのアップロードをできるようにします。
+SecRequestBodyInMemoryLimit 524288000
+SecRequestBodyLimit 524288000
+
+## テスト用の検知パラメータを付け加えます。
+    SecRule ARGS:modsecparam "@contains test" "id:4321,deny,status:403,msg:'ModSecurity test rule has triggered'"
+
sudo apache2ctl configtest

Syntax OKを確認します。

sudo systemctl restart apache2.service
systemctl status apache2.service

active (running) を確認します。

mod_security動作確認

  1. ブラウザで、上記の設定を行ったWebサイトにアクセスし、閲覧できることを確認します。
  2. アドレスバーの末尾に?modsecparam=testを追加してアクセスします。

のように、アクセスできないことを確認します。

また、サーバでも

sudo cat /path/to/sites_log/directory/sites_error.log

※ログの格納場所やログの名前は自分の環境に合わせます。

を開き、

ModSecurity: Access denied with code 403 (phase 2). String match "test" at ARGS:modsecparam. [file "/etc/apache2/sites-enabled/your_site.conf"] [line "53"] [id "4321"] [msg "ModSecurity test rule has triggered"] [hostname "host_address"] [uri "/"] [unique_id "xxxxxxx"]

のように、エラーが発生していることを確認します。

備考

Wordpress、Redmine等のWebアプリは自身の操作によって「不審なアクセス」として遮断することが極めてよくあります。(偽陽性)

そのため、テストを行った後は

## ModSecurity有効化
#SecRuleEngine On
## ModSecurity検知モード
### 検知モードで動かす場合はSecRuleEngine Onをコメントアウトしてこちらを有効化します
SecRuleEngine DetectionOnly

として検知モードとして動かした方が良いでしょう。

Mod_Securityで特定のルールを無視する設定(Nextcloudでの偽陽性を排除)

Nextcloudにmod_securityを導入するに当たり、気をつけなければならないのがファイルの閲覧や登録、入力処理中にMod_securityが不審な処理として判断してしまうこと(偽陽性)です。

そこで、

  1. 偽陽性と思われるログの調査
  2. 調査時の補助線引き
  3. 偽陽性になるルールを無視する設定

を行います。

ログ確認

/var/log/nextcloud_error.logから、以下のようなログを見ました。

[Wed Sep 11 16:35:02.048442 2024] [security2:error] [pid 32762:tid 32762] [client aaa.bbb.ccc.ddd:56994] [client aaa.bbb.ccc.ddd] ModSecurity: Warning. Operator GE matched 5 at TX:inbound_anomaly_score. [file "/usr/share/modsecurity-crs/rules/RESPONSE-980-CORRELATION.conf"] [line "92"] [id "980130"] [msg "Inbound Anomaly Score Exceeded (Total Inbound Score: 5 - SQLI=0,XSS=0,RFI=0,LFI=0,RCE=0,PHPI=0,HTTP=0,SESS=0): individual paranoia level scores: 5, 0, 0, 0"] [ver "OWASP_CRS/3.3.5"] [tag "event-correlation"] [hostname "nextcloud.hoge.com"] [uri "/ocs/v2.php/apps/user_status/api/v1/heartbeat"] [unique_id "ZuFIJU_udFaqxqrJvRLaPQAAAAA"]

ここで見たいのは

です。

ログ確認のワンライナー

これらを確認するため、copilotの助けを借りてawkスクリプトを生成します。

awk '/ModSecurity/ {
ip = gensub(/.*\[client ([0-9.]+):.*/, "\\1", "g", $0);
rule_id = gensub(/.*\[id "([0-9]+)"\].*/, "\\1", "g", $0);
print rule_id, ip;
}' /var/log/nextcloud/nextcloud_error.log | sort | uniq -c

これを実行したところ、Mod_Securityがエラーとして検知したログの中から

     36 911100 127.0.0.1
    267 911100 aaa.bbb.ccc.ddd
     65 920420 aaa.bbb.ccc.ddd
     36 949110 127.0.0.1
    267 949110 aaa.bbb.ccc.ddd
     36 980130 127.0.0.1
    267 980130 aaa.bbb.ccc.ddd

という結果を確認しました。127.0.0.1はローカルアドレス、aaa.bbb.ccc.dddも自分がアクセスしてきたIPアドレス。この間、自分がしていたのはNextcloudの設定変更やファイルの閲覧のみです。

Mod_securityが検知したルールIDを「偽陽性」と判断し、処置していきます。

Mod_Securityで特定のルールを検知させない処理

Apacheのバーチャルサイトで設定しているという形です。

設定ファイルの修正

sudo cp -ci /etc/apache2/sites-available/nextcloud.conf /path/to/backup/directory/nextcloud.conf.$(date +%Y%m%d)

設定ファイルやバックアップディレクトリは自分の環境に合わせます。

diff -u /path/to/backup/directory/nextcloud.conf.$(date +%Y%m%d) /etc/apache2/sites-available/nextcloud.conf

エラー無く、差分も表示されていなければバックアップは成功です。

/etc/apache2/sites-available/nextcloud.confを以下のように修正していきます。(要root権限)

# Mod_security
## 最初は検知モード

SecRuleEngine DetectionOnly

## 偽陽性と判断したID
SecRuleRemoveById 911100
SecRuleRemoveById 920420
SecRuleRemoveById 949110
SecRuleRemoveById 980130
diff -u /path/to/backup/directory/nextcloud.conf.$(date +%Y%m%d) /etc/apache2/sites-available/nextcloud.conf

SecRuleRemoveById IDで、これにマッチするパターンは無視します。

 ## 最初は検知モード
 
 SecRuleEngine DetectionOnly
+
+## 偽陽性と判断したID
+SecRuleRemoveById 911100
+SecRuleRemoveById 920420
+SecRuleRemoveById 949110
+SecRuleRemoveById 980130
+
 </VirtualHost>

設定ファイルの設定反映

sudo apache2ctl configtest

Syntax OKを確認します。

sudo systemctl restart apache2.service
systemctl status apache2.service

active(running)を確認します。

動作確認

ターミナルで

tail -f /var/log/nextcloud/nextcloud_error.log

としてエラーログを流します。(エラーログは自分の環境に合わせます)