読者です 読者をやめる 読者になる 読者になる

俺の報告

RoomClipを運営するエンジニアの日報(多分)です。

日報 #79 - mod_dosdetectorの導入

超絶ナチュラルに昨日サボりましたが、
俺あるあるですので、気にせず。

さて、実はサーバの根幹部分に色々手を加えておりまして、
ストレスフルな日々でございます。
なんか知らないけど、いつまでだってもLoadAverageが「やや高い(問題があるレベルじゃない)」という、
生ぬるくいじめられている感じです。
メモリのcacheが増えたり、apcのキャッシュが貯まれば落ち着くのでしょうか…

さて、本日はUbuntuapacheにdosdetectorをぶっこむ作業について共有いたします。
DoS対策にはmod_evasiveとmod_dosdetectorがあるようですが、
前者はプロセス毎へのアクセス回数でみているらしいので、
使うなら後者がよいということでそうします。

あと、LBやリバースプロキシのようなものをつかってWebサーバへの直近アクセスが固定されているような時は、 forwardのIPをとってこなくてはならないので、その辺の対策ようにmod_extract_forwardedも導入します。
とはいえ、dosdetectorの設定をみるとDoSForwardedという項目があるので、もしかしたら対応しているかもしれません。
正確には確認してませんが。
でもまぁどの道、既存のLogFormatなどでもフランクにRemoteIPを使うので、
フォワードにしておくのは意味のあること判断して導入します。

まず、mod_extract_forwardedから。

http://blog.yshh.jp/blog/2010/12/09/mod_extract_forwarded%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%ABfor-apache2-2-on-centos5/

このサイトのとおりでございます。別段触れることありません。
patchコマンドの書き方を勉強した程度です。
MEFacceptの設定はELBならallにしておく必要があります。
ELBのIPは信じてはいけませんので。

続いてメインのdosdetectorです。
dosdetector-forkなる改造版もあるようですが、最終コミットが6年前とかなので、
本家を使うのが吉ということで、そっちのgitからいきます。

cd ~
git clone https://github.com/stanaka/mod_dosdetector.git
cd mod_dosdetector
cp Makefile Makefile_buckup
sed -i -e "s/APXS=\/usr\/bin\/apxs/APXS=\/usr\/bin\/apxs2/g" Makefile
sed -i -e "s/APACHECTL=apachectl/APACHECTL=apache2ctl/g" Makefile

後半いじってるのは、apachectlの仕様とapxsの仕様に合わせて変えないとダメです。
Make過程でapacheにa2enmodするのと、apache再起動をするときにサービス名を使うみたいなので。
んで、あとはapache2.confに書き加える設定。

<IfModule mod_dosdetector.c>
 # 使うならオンにしましょう
 DoSDetection on
 # DoS攻撃判定をする為の計測時間
 DoSPeriod 1
 # DoSPeriodの間にDoS攻撃の嫌疑をかけるアクセスカウント(ちなみにこれを突破したら変数SuspectDoSが1になる)
 DoSThreshold 20
 # DoSPeriodの間にDoS攻撃と確定するアクセスカウント(変数SuspectHardDoSが1になる)
 DoSHardThreshold 30
 # DoS攻撃認定されてから解除までの時間(秒)
 DoSBanPeriod 60
 # このモジュールが一部使うメモリの名前?よく分からん
 DoSShmemName dosshm
 # 嫌疑をかけるIPの保存数
 DoSTableSize 100
 # X-Forwarded-For headerをIPとして扱うかどうかのチェック
 DoSForwarded on
 # 無視リスト。ここではjsとcssと画像全部
 DoSIgnoreContentType (image/|text/css|text/javascript)
</IfModule>

さて、dosdetectorのいいところは、DoSと判定したら変数SuspectDos(またはSuspectHardDoS)を1にするだけのところ。
その後の対応はこちらで自由に設定できます。
で、大体503とかに飛ばすと思うのだけど、
普通VirturalHostのDirectory領域にRewriteを書いていると思うのでそこに追記します。
例えば、/etc/apache2/sites-avairableのdefaultとかに記載されているRewrite部分にRewriteCondを挿入します。
要は条件分岐させます。

# for DoS attack
RewriteCond %{ENV:SuspectDoS} .+ [OR]
RewriteCond %{ENV:SuspectHardDoS} .+
# クラスAのローカルIPアドレス帯を全て除外
RewriteCond %{REMOTE_ADDR} !^(10\.[0-9]+\.[0-9]\.[0-9])$
# クラスBのローカルIPアドレス帯を全て除外
RewriteCond %{REMOTE_ADDR} !^(172\.(1[6-9]|2[0-9]|3[0-1])\.[0-9]+\.[0-9]+)$
# クラスCのローカルIPアドレス帯を全て除外
RewriteCond %{REMOTE_ADDR} !^(192\.168\.[0-9]+\.[0-9]+)$
# 対クローラー排除
RewriteCond %{HTTP_USER_AGENT} !(google|yahoo|msn|bing) [NC]
RewriteRule .* - [R=503,L]

ずらずらとCondを並べ立てて、最終的に
RewriteRule .* - [R=503,L]
しています。503に飛ばせということですね。
以上、すげーシンプルかつ簡単なDoS対策でした。
DDoSに対してはまた別途対策が必要なので、のちほどー。
疲れたぜ…まだロードアベレージ高い…どうにかならんかね、このじゃじゃ馬。