Apache DoS対策 mod_evasive の導入

# 想定環境
CentOS 6 または 7

```shell-session
# rpm -q mod_evasive
mod_evasive-1.10.1-10.el6.x86_64

# rpm -q mod_evasive
mod_evasive-1.10.1-22.el7.x86_64
```

# 効能
しつこいHTTP DoSアタックやブルートフォースアタックに。

# 導入前の検討事項

## ホワイトリスト

下記のケースでは、アクセス元IPアドレスをホワイトリストに登録することを検討しましょう。

- 決済モジュールを導入していて通知のある場合、その通知サーバー
- ロードバランス構成の場合、ロードバランサ(冗長構成の場合はその全て。大抵クラウド管理画面で確認できます)
- 死活監視サーバー
- CDN
- 検索ボット
- その他に自サイトをキックしてくる連携プログラム

# 設定ファイル

設定ファイルは /etc/httpd/conf.d/mod_evasive.conf です。
デフォルトの設定は、下記の通りです。

```mod_evasive.conf
LoadModule evasive20_module modules/mod_evasive20.so

<IfModule mod_evasive20.c>
    DOSHashTableSize    3097
    DOSPageCount        2
    DOSSiteCount        50
    DOSPageInterval     1
    DOSSiteInterval     1
    DOSBlockingPeriod   10
    #DOSEmailNotify      you@yourdomain.com
    #DOSSystemCommand    "su - someuser -c '/sbin/... %s ...'"
    #DOSLogDir           "/var/lock/mod_evasive"
    #DOSWhitelist   127.0.0.1
    #DOSWhitelist   192.168.0.*
</IfModule>
```

## ブラックリストの動き

- クライアントIPアドレスがブラックリストに登録されていれば、403 Forbidden を返す。
- 同一ページに 2回/秒 のアクセスがあれば、ブラックリストに登録する(DOSPageCount/DOSPageInterval)
- 同一サイトに 50回/秒 のアクセスがあれば、ブラックリストに登録する(DOSSiteCount/DOSSiteInterval)
- ブラックリスト登録後10秒間 403 Forbidden を返す。新にアクセスがあれば、その都度10秒延長される(DOSBlockingPeriod)

## DOSLogDir

ブラックリスト登録時、このディレクトリ下に `dos-<IP>` という名前でファイルが作成されます。
これは DOSEmailNotify・DOSSystemCommand の実行を制御するロックファイルです。
DOSEmailNotify・DOSSystemCommand はロックファイル作成時にのみ実行され、既にロックファイルが
存在する場合は実行されません。

また、ブラックリスト登録時に `/var/log/messages` にログが出力されますが、これもロックファイル作成時のみ出力されます。

>Jun 18 18:53:28 sv mod_evasive[21663]: Blacklisting address 127.0.0.1: possible DoS attack.


デフォルトではロックファイルを消さないので、DOSEmailNotifyを設定しても一度しか送信されません。一時間ごとにメールを受けとっていもいい場合は、ロックファイルの削除をスケジュールする設定をします。

```mod_evasive.conf
    DOSSystemCommand    "echo rm -f /tmp/dos-%s | SHELL=/bin/sh at now + 60 minutes"
```

ロックファイル作成後、1時間後に削除します。

デフォルト値は /tmp です。

<!---

デフォルト値は /tmp ですが、専用のディレクトリ /var/lock/mod_evasive を指定しましょう。
/tmpは再起動時に自動で消えるが、専用ディレクトリは自分で消さないといけない。それを考えると/tmpでいいか。
centos7 の /var/lock は tmpfs
https://qiita.com/suemoc/items/e29285e8e67263298f35
-->

ロックファイルの中身は、ロックファイルを作成したhttpdのプロセスIDです。

## DOSEmailNotify

デフォルトでは通知メールの件名が空ですが、設定可能です。

```mod_evasive.conf
    DOSEmailNotify      "-s 'DoS Attack Alert' me@example.com"
```

## DOSSystemCommand

TODO: iptables/ipset と連携

# 導入手順

rpmパッケージをインストールする

```shell-session
# yum -y install mod_evasive
```

<!---
必要なディレクトリを作成して、各設定を調整します。

```shell-session
# mkdir /var/lock/mod_evasive
# chown apache: /var/lock/mod_evasive
# vi /etc/httpd/conf.d/mod_evasive.conf
```

DOSLogDirのコメントを外し、必要なら他のパラメータを調整します。

```mod_evasive.conf
    DOSLogDir           "/var/lock/mod_evasive"
```
-->

初回導入時は、Apacheを再起動して反映します。

```shell-session
# service httpd restart
```

設定変更時は、リロードで反映します。

```shell-session
# service httpd reload
```

# 動作確認

連続アクセスで、途中から 403 Forbidden になる事を確認します。

```shell-session
# yes 'exec 4<>/dev/tcp/127.0.0.1/80; printf "GET / HTTP/1.0\r\n\r\n" >&4; head -1 <&4' | head -100 | bash
HTTP/1.1 200 OK
HTTP/1.1 200 OK
... # 200 OK の繰り返し
HTTP/1.1 200 OK
HTTP/1.1 403 Forbidden
HTTP/1.1 403 Forbidden
... # 403 Forbidden の繰り返し
HTTP/1.1 403 Forbidden
```

syslogにログが出力されている事を確認します。

```shell-session
# grep mod_evasive /var/log/messages
Jun 18 18:53:28 sv mod_evasive[21663]: Blacklisting address 127.0.0.1: possible DoS attack.
```

ロックファイルが作成されます。

```shell-session
# ls /tmp/dos-127.0.0.1
/tmp/dos-127.0.0.1
```

付属のtest.plは、最近のapacheでは 400 Bad Request になって使えません。リクエストの改行コードがCRLFでないためです。

# 切り戻し手順

mod_evasive.confのLoadModuleをコメントアウトします。

```mod_evasive.conf
#LoadModule evasive20_module modules/mod_evasive20.so
```

Apacheを再起動して反映して、モジュールをアンロードします。

```shell-session
# service httpd restart
```

# 参考情報

[本家](https://github.com/jzdziarski/mod_evasive)