こちらの記事では、最速のナイフであるmod_aliasと、強力な拳銃であるmod_rewriteの特徴、そして「速度と役割のトレードオフ」についてお話ししました。
ここからは、筆者が実際に運用している atelier.reisalin.com の設定ファイルを元に、この2つの武器をどのように組み合わせ、悪意あるボットや過剰なクローラーを迎撃しているのか。その具体的な防衛システム、名付けて「Jailhouse Lock(ジェイルハウスロック)」の核となるmod_rewriteモジュールについてお話しします。
mod_rewriteとは?
mod_rewriteは、リクエストされたURLをファイルシステム上の特定の場所にマッピング(転送・代替)したり、別のURLへリダイレクトしたりするための、Apacheの拡張モジュールです。(そのため、多くのディストリビューションではインストールと同時に機能が有効化されていないことが多数あります。)
Ubuntu系であれば
sudo a2enmod rewrite
sudo systemctl restart apache2.service
で有効化されます。
再掲:mod_alias との違い
どちらも「URLを操作する」という意味では同じですが、そのアプローチと内部処理の複雑さに大きな違いがあります。
| 項目 | mod_alias | mod_rewrite |
|---|---|---|
| コンセプト | 単純なマッピングとリダイレクト | 強力なURLカスタマイズと書き換え |
| 判定基準 | 単純な前方一致(接頭辞マッチ) | 正規表現、Cookie、環境変数、時間など |
| 処理速度 | 非常に高速(軽量) | やや低速(ルール毎に正規表現エンジンが動く) |
| 設定の難易度 | 簡単(初心者向け) | 複雑(記述ミスで無限ループが起きやすい) |
| 主な用途 | フォルダの共通化、単純なサイト引っ越し | 綺麗に整形されたURL(Smart URL)の実現、複雑な条件分岐 |
最大の違い:正規表現と条件分岐の有無
mod_aliasは、URLの「先頭が一致しているか」という単純な比較しか行いません。
一方、mod_rewriteは「リクエストがGoogle Chromeから来たら」「平日の昼間なら」「Cookieに特定の文字が含まれていたら」といった、高度な条件分岐(RewriteCond)や、正規表現を使った自由自在なURLの作り替え(RewriteRule)が可能です。
筆者の設定内容抜粋
まずは、実際に稼働している設定の抜粋をご覧ください。
<VirtualHost *:80>
ServerName atelier.reisalin.com
RewriteEngine On
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>
<VirtualHost *:443>
ServerName atelier.reisalin.com
# ----- ログの選別と抑制 -----
SetEnvIf Remote_Addr "192.0.2.1" dontlog
SetEnvIfNoCase User-Agent "Googlebot" dontlog
SetEnvIfNoCase User-Agent "GoogleOther" dontlog
# ModSecurity等、WAFで捕獲したエラーはログを肥大化させない
SetEnvIf MSC_RULE_ID "4009" dontlog
CustomLog /var/log/apache2/atelier_access.log combined env=!dontlog
DocumentRoot /home/www-data/atelier/public
# --------------------------------------------------
# 第一層:【mod_alias】によるハニーポットへの一撃転送
# --------------------------------------------------
<IfModule mod_alias.c>
# 監獄(Jailhouse)となる隔離ディレクトリを定義
Alias /__jailhouse_lock /home/www-data/nepenthes
# 存在しないはずの脆弱性パスへのアクセスを最速でトラップへ
Alias /wp-login.php /home/www-data/nepenthes/login.html
Alias /wp-admin /home/www-data/nepenthes/login.html
Alias /.git /home/www-data/nepenthes/git.html
Alias /assets-archive /home/www-data/nepenthes/login.html
<Directory /home/www-data/nepenthes>
Options -Indexes
AllowOverride None
Require all granted
</Directory>
</IfModule>
# --------------------------------------------------
# 第二層:【mod_rewrite】による動的・精密迎撃
# --------------------------------------------------
<Directory /home/www-data/atelier/public>
Options -MultiViews
AllowOverride All
Require all granted
<IfModule mod_rewrite.c>
RewriteEngine On
# 【迎撃フェーズ1】悪質botフラグが立っている通信の隔離
RewriteCond %{ENV:bad_bot} =1
RewriteCond %{REQUEST_URI} !^/__jailhouse_lock/
RewriteRule ^.*$ /__jailhouse_lock/topgear.html [L,E=dontlog:1]
# 【迎撃フェーズ2】特定の重いコンテンツを狙った過剰クローラー対策
SetEnvIf Request_URI "^/projects/zettel" is_zettel
# 大量のカンマ区切り(%2C)や、極端に長い(150文字以上)悪意あるクエリを検知
SetEnvIf Query_String "tag=.*(%2[cC]|,|%e3%80%81).*(%2[cC]|,|%e3%80%81).*(%2[cC]|,|%e3%80%81)" bad_tag_stacking
SetEnvIf Query_String "tag=.{150,}" bad_tag_stacking
# 特定ページ、かつ異常クエリというパズルが揃った瞬間に500エラーで即撃破
RewriteCond %{ENV:is_zettel} 1
RewriteCond %{ENV:bad_tag_stacking} 1
RewriteRule ^ - [E=dontlog:1,R=500,L]
</IfModule>
</Directory>
</VirtualHost>
防衛ストーリー:ナイフで受け流し、拳銃で仕留める
この「Jailhouse Lock」システムは、先の記事で述べたmod_alias(ナイフ)とmod_rewrite(拳銃)の特性をコンビネーションとして昇華させたものです。
この言葉は大好きなので何度でも再掲しますが:『MASTERキートン』のプロフェッサーの言葉。
「やめておけ」
「…………」
「拳銃の方が、ナイフよりも速いと思っているんだろう。
だが、拳銃はデリケートな道具だ。
弾が出ないかもしれないし、
思い通り的に当たるとは限らん。
おまけに拳銃は、
抜き、構え、引き金を引くまでに三動作(スリーアクション)……
その点ナイフは、一動作(ワンアクション)で終わる。
この距離なら、絶対に俺が勝つ!!
どうする? それでもやってみるかね?」
これはナイフの方が有利という単純な比較論ではなく、
「この距離ではナイフが有用」だが、「ある程度のアクションや破壊力が必要な場合は拳銃が必要なるケース」というお話と筆者は捉えています。
第一層(mod_alias):無差別スキャンを「無駄なく」いなす
サイトがWordPressで作られていようがいまいが、botは機械的に /wp-login.php や /.git を探して叩いてきます。これらはURLの文字列そのものが標的であるため、複雑な条件分岐は不要です。
ここで登場するのがナイフの速度を持つ mod_alias です。
# 監獄(Jailhouse)となる隔離ディレクトリを定義
Alias /__jailhouse_lock /home/www-data/nepenthes
# 存在しないはずの脆弱性パスへのアクセスを最速でトラップへ
Alias /wp-login.php /home/www-data/nepenthes/login.html
Alias /wp-admin /home/www-data/nepenthes/login.html
この部分。ボット、クローラー、悪意ある攻撃者が挨拶代わりに上記のサイトへのURLに一致した瞬間に、メインアプリケーション(PHPなど)を一切起動させることなく、最速でハニーポット(ダミーのHTML空間 nepenthes)へと受け流します。サーバーのリソースを1ミリも無駄にしない、ナイフならではの「一動作(ワンアクション)」の防御です。
第二層(mod_rewrite):パズルを解き明かし「精密に」射抜く
しかし、中には特定のコンテンツ(例:負荷の重い検索機能など)に対して、URLの引数(クエリ)を巧妙に変えながら何度もクロールしてくる、たちの悪いボットがいます。
URLの文字しか見られない mod_alias では、URLの後ろに付く ?tag=xxx の中身まで検知することはできません。ここで拳銃である mod_rewrite を引き抜きます。
RewriteCond %{ENV:is_zettel} 1
RewriteCond %{ENV:bad_tag_stacking} 1
RewriteRule ^ - [E=dontlog:1,R=500,L]
「特定のコンテンツへのアクセスである(is_zettel)」
「かつ、タグの指定が異常に長い、または大量に詰め込まれている(bad_tag_stacking)」
この複数の条件が上から順にカチリと噛み合った瞬間、mod_rewrite は狙い違わず [R=500,L] という弾丸を放ち、リクエストを強制終了させます。同時に [E=dontlog:1] フラグを立てることで、ボットの嫌がらせによる「ログファイルの肥大化(ディスク容量の圧迫)」という二次災害まで綺麗に防いでみせるのです。
なぜ nginx ではなく、Apache なのか?
近代的なWebサーバーとしてnginxが台頭する中、なぜ筆者がApacheを用いる理由は以下の通り。
Apacheの持つ「上から下に流れる手続き型の思考」が、このような防衛ロジックを組む際に圧倒的に人間にとって直感的だからです。
もし、これと同じ「AかつBの条件を満たした時だけ、500エラーで弾いてログを消す」という処理をnginxで実装しようとすると、事情が変わってきます。nginxには条件を連鎖させる RewriteCond のような仕組みがなく、また if 文の挙動が非常にデリケート(通称:If is Evil)であるため、以下のような不格好な「変数ハック」を強いられます。
例えば、これと同等の機能をnginxでやろうとすると
# nginxで複数の動的条件を重ねる場合の苦肉の策
set $block_trigger "";
if ($is_zettel) { set $block_trigger "Y"; }
if ($bad_tag_stacking) { set $block_trigger "${block_trigger}Y"; }
if ($block_trigger = "YY") {
return 500;
}
かなりifの入れ子構造が面倒になります。それに対し、Apacheは「この条件を満たし、さらにこの条件も満たしたら、このルールを適用して終了!」と、設計思想をそのまま設定にぶち込む強みがあります。
結び:適材適所の美学
強力な道具は、それ単体で振り回しても真価を発揮しません。
- 固定の攻撃パスは、システムに最も負荷をかけない
mod_aliasで門前払いする。 - 動的なパラメータや環境変数が絡む高度な迎撃は、
mod_rewriteの柔軟性を活かしてピンポイントで処理する。
速度のナイフと、射程の拳銃。
この2つのモジュールを「適切なコンテキスト」で併用することで、設定ファイルそのものである程度の防御は出来るというお話です。
余談ではありますが:mod_rewriteは強力ですが、設定を一行誤れば自分自身が500エラーの被害者になります。
「『いい鉄砲は打ち手を選ぶ』ってことわざ知ってるか?
威力のある鉄砲は その分扱いも難しく危険
だから未熟者が使うと打ち手の方がケガをするってことさ」
という『ONE OUTS』で渡久地が言った言葉を持って、本記事を締めくくります。
コメントを残す