雑多な事柄を無理矢理一つにまとめるエッセイに似た何か『IDEA SPHERE』の一節。
この大本のきっかけとなった「なぜ、切り戻しが大切か」という原体験を述べようと思います。
遭難、一歩手前。
話はかなり昔。筆者が訪れたベルナー・オーバーラント地方の4泊滞在。
ものすごくさっくり言うと
- 観光ガイド地図では近そうだからと歩くのを試みた。
- 人気が無い道だけど下れば平気と思い込んでいた。
- 軽食を取っているときにユングフラウの雲に傘がかかっていた
- これはヤバいと引き返し
- 駅に着くと同時に雨
- そして本当に正しい道が分かった
この、「一歩でも間違えば客死寸前」というよりも「生きていたのが不思議」という体験。なぜ、人はこれに陥るのか?
それを紐解いていきます。
STOPの原則とサンクコスト
その背景には、人間の判断を狂わせる強力な心理的トラップと、それを打破するための基本的なプロトコルが欠けていたことにあります。
ここで重要になるのが、「サンクコスト(埋没費用)のバイアス」と、回避策としての「STOP」の概念です。
サンクコストの罠:「ここまで来たから」という呪縛
「せっかくここまで歩いたのだから」「もう少し進めば着くはずだ」という思考こそが、サンクコストのバイアスです。それまでに費やした時間や労力を惜しむあまり、客観的に見て「引き返すのが正解」という状況でも、損を認めたくない心理から無理な続行を選択してしまいます。
ガチャなどでも「10連でお目当てのSSRが引けないから次の10連こそ」で石を使い切り、追い課金をしてドツボにハマるアレです。
STOP:冷静さを取り戻すための技術
このバイアスを断ち切り、致命的な結果を回避するために有効なのが、登山の危機管理などでも用いられる「STOP」の法則です。
- S (Stop) / 止まる:
- 異変を感じたら、物理的に足を止める。焦燥感から逃れるための第一歩です。
- T (Think) / 考える:
- 現在の状況を冷静に分析する。感情を切り離し、事実のみを見つめます。
- O (Observe) / 観察する:
- 周囲の天候、道筋、自分の体力を客観的に見る。「雲に傘がかかっている」という兆候を見逃さないことです。
- P (Plan) / 計画する:
- 進むべきか、退くべきか。最善の安全策を再構築する。
「進む誘惑」を振り切り、「留まる(あるいは引き返す)勇気」を持つこと。この判断の遅れが、システム運用における障害の深刻化や、山岳における遭難の引き金となります。私の体験を、もう少し詳しく紐解いていきましょう。
いつものように長い全文(マクラ)と筆者の実例というスタイルです。
当初の「問題」:タグの数珠つなぎ検索
筆者が運営しているRedmineサイト。特定のプロジェクトページ(/projects/hoge)に対し、以下のようなリクエストが大量に発生していました。
GET /projects/hoge/search?tag=A,B,C,D,E,F...
カンマ(,)やURLエンコードされた区切り文字を使い、タグを5個も10個も連結して検索を繰り返す挙動です。これは明らかにサイト構造を網羅しようとするスクレイピング(採取)ボットの動きであり、アプリケーションのDB負荷を無駄に高めていました。
当初の「改善案」:ModSecurityでの防御
この「異常なタグの連結」を検知するため、ModSecurity(WAF)にカスタムルールを投入しました。
# 引数 "tag" の中にカンマが3つ以上あればブロック
SecRule REQUEST_URI "@contains /projects/hoge" \
"id:10010,phase:1,chain,deny,status:404,nolog,msg:'Excessive tag stacking'"
SecRule ARGS:tag "(?i)(?:%2c|,).?(?:%2c|,).?(?:%2c|,)"
「404を返し、かつ nolog で静かに処理する」という、完璧な罠を仕掛けたはずでした。
失敗:静寂を破る「Googlebot」のログ浮上
ルールを適用した直後、おかしな現象が起きました。これまでアクセスログへの出力を抑制(dontlog)していた Googlebot などの正規クローラーのログが、突如として出力され始めたのです。
ボットを黙らせるために設定を追加したのに、逆に「普段は隠れているはずのログ」が溢れ出す本末転倒な事態。ここで私は、
「軽微な修正ですぐに直るはずだ」
という思い込みに囚われました。ModSecurityのフラグをいじり、設定の微調整を繰り返します。しかし、ログの奔流は止まりません。
画面を埋め尽くす不毛なログ。高まる焦燥感。私は「なぜ」と自問しながら、STOP原則から最も遠い場所にいました。
踏み止まる勇気:サンクコストを捨てる「STOP」
「せっかくここまでルールを書いたのだから」
「あと一行修正すれば動くはずだ」
この心理こそが、ベルナー・オーバーラントの脇道で感じた「進む誘惑」、すなわちサンクコストのバイアスでした。
混濁する思考を救ったのは、かつての教訓から学んだ「STOP」の原則です。
- S (Stop):
- キーボードを叩く手を止め、一旦モニターから目を逸らす。
- T (Think):
- 「なぜ、本来無関係なログが出るのか?」という根本に立ち返る。
- O (Observe):
- 自分の呼吸が浅くなっていること、そして「何か食べて落ち着こう」と、判断する。
- P (Plan):
- 復旧策はそこからでも遅くない、と計画する。
炭酸水で出したお茶を飲み、空腹を満たして一息ついたとき、ようやく冷静な判断が戻ってきました。
「今の自分は、壊れた防衛線を直そうとして、さらに傷を広げている」と。
ここで私は、事前に取っておいたバックアップによる「切り戻し」を決断します。設定を完全に修正前の状態へロールバックしたのです。
失敗の原因:「ModSecurityの干渉」
真っ新な状態に戻って観察して、ようやく原因が見えてきました。ModSecurity の phase:1 で deny を行うと、Apache の処理サイクルがその時点で中断してしまいます。
本来、Apache側で「このUser-Agentならログを出さない」という env=!dontlog の判定を通る前に、WAF側の処理が割り込んだことで、ログ制御のフラグ管理がバイパスされていたのです。
次のアプローチ:Apacheレイヤーでの「入口断絶」
WAFに固執するのをやめ、より手前の Apache レイヤー(mod_rewrite)で、物理的に遮断とログ抑制を同時に行う作戦に切り替えました。
また、ボットが「カンマ」を「読点(、)」に変えてフィルターを回避しようとする動きも見せたため、それらも網羅する正規表現に強化しました。
修正後の設定(.conf)
<IfModule mod_rewrite.c>
RewriteEngine On
# 1. パスと異常なクエリ(タグ3つ以上のスタッキング)を特定
SetEnvIf Request_URI "^/projects/hoge" is_target_path
SetEnvIf Query_String "tag=.(%2c|,|%e3%80%81).(%2c|,|%e3%80%81).(%2c|,|%e3%80%81)" bad_bot
# 2. 条件一致ならログを抑制(dontlog)しつつ、404で追い返す
RewriteCond %{ENV:is_target_path} 1
RewriteCond %{ENV:bad_bot} 1
RewriteRule ^ - [E=dontlog:1,R=404,L]
</IfModule>
成功:ログの静寂
この設定を反映した結果、効果は絶大でした。
- 採取ボット:
- 404を返されつつ、
dontlogによってアクセスログから完全に姿を消しました。
- 404を返されつつ、
- 正規ユーザー:
- 普段通り
200 OKでアクセスでき、ログも正しく記録されます。
- 普段通り
- Googlebot:
- 以前のように、音もなく巡回を続けています。
一度すべてを白紙に戻す「勇気」が、結果として最短ルートでの解決を導いたのです。
まとめ
きちんとした手順に則ったリリース作業などと違い、個人でやっているサイト運営は「このぐらいなら大丈夫だろう」が甚大な被害を生むことが多々あります。
これこそ、
- プログラム1つの更新
- 設定ファイルの修正
- コマンドミス
などで、サーバは瓦解します。しかも、自分の指先一つで壊れるのですから、何があっても
誰かのせいにしたいが自分の顔しか思い浮かばない
I'm casting around in my head for someone to blame and it's just me, keeps coming back at me.
と筆者が冒頭で述べたことであり、『むこうぶち』で江崎が言った
「船が陸にたどり着く寸前に生憎の嵐……
どうすればいいと思います?
いったん沖に引き返すんですよ
船ってのは水に浮かぶようにできているんです
無闇に上陸を焦って座礁する事が一番怖い」
を自分が引き合いに出しておきながらそれを無視したという超特大のブーメランが自分に向かって飛んできたというお話しでした。