月: 2026年7月

セキュリティデッキを組もう:ModSecurity Request-900-Exclusionの編集意義

MtGやDMを遊んだことがあるのであれば聞いたことがあるだろう

「カードはルールに勝つ
 (カードの効果とルールが直接矛盾した場合、カードの効果を優先する)」

という大原則。

「カードを2枚引く」

というシンプルなテキストであっても、通常、プレイヤーは1ターンに1枚のみカードを引くと言うルールがありますが、カードにそう書かれていればそのルールを無視した挙動が可能になります。

一見すると乱暴な言葉ですが、実際にはゲームデザイン上もっとも重要な考え方の一つです。

基本ルールは全員共通。しかし、カードには「この場合だけは例外」が書かれています。だからこそ何万種類ものカードが共存できます。

実は、この考え方は ModSecurity にも、そのまま当てはまります。

今回、私がModSecurityに導入している「REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf」について解説します。

REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.confとは?

ModSecurityで本格的な防御を行う際、多くの人が「OWASP CRS(Core Rule Set)」という、世界中のセキュリテイ専門家が作った強力な既製ルール集を導入します。

CRSは非常に優秀ですが、何千もの緻密なルールが詰まっているため、上から順にすべてをチェックするとそれなりの処理コスト(CPUやメモリ)がかかります。

また、これは非常にデリケートでガチガチなので

  1. ファイルをアップロードした
  2. コードを書き込んだ
  3. クリックを繰り返した

だけで「こいつは怪しい動きをしている」として、アクセスそのものを遮断する「偽陽性」が発生します。

そこで、膨大なCRSの本体を書き換えることなく

  1. プログラムのコードやコマンドラインなどを投稿するのはOK
  2. だが、それを使った攻撃は許さない
  3. 複雑なスキャンは不要。「悪・即・斬」レベルで不審な攻撃をたたき落とす
  4. 逆に「こいつは面白い動きをするからハニーポットに誘導しよう」

などの「デッキを作るような感覚で」膨大なCRSを制御する方法として用意されているのが、REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf(以下、900番BEFOREルール)です。

設置例

筆者環境

  • ModSecurity 2.9.7
  • Core Rule Set 3.3.5
  • Apache 2.4
  • Ubuntu 24.04

どこに置くか?

筆者環境の場合は

/usr/share/modsecurity-crs/coreruleset/rules配下のREQUEST-900-EXCLUSION-RULES-BEFORE-CRS.confですが、

/home/hoge/script/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf

など、自分がメンテナンスしやすい位置にこのファイルの実体を置いておき、ln -sfでシンボリックリンクを張る方が非常に簡単です。というのも、「このデッキ調整」はデリケートな作業なので何回も何十回も調整が必要になります。そのたびに深い階層を掘ってファイルを編集するのは効率的ではありません。

とはいえ、シンボリックファイル is Evil だったりrootアカウントしかないとかいう方はいるので流儀に合わせてください。

ケーススタディ

効果的なカスタム案

筆者が実際に使っている中で最も効果的なルールがこれです。

# IPアドレス直打ちアクセス対策 
SecRule REQUEST_HEADERS:Host "@rx ^[\d.]+(:\d+)?$" \
    "id:10004,\
    phase:1,\
    deny,\
    status:404,\
    log,\
    msg:'[CUSTOM RULE] Host header is a numeric IP address (incl port). Blocked immediately.',\
    tag:'application-attack',\
    tag:'PROTOCOL_VIOLATION/INVALID_HREQ'"

# Hostヘッダーが存在しない場合は即ブロック
SecRule &REQUEST_HEADERS:Host "@eq 0" \
    "id:10005,\
    phase:1,\
    deny,\
    status:404,\
    log,\
    msg:'[CUSTOM RULE] Missing Host Header. Blocked immediately.'"
  • id:10004:
    • 正規表現 @rx ^[\d.]+(:\d+)?$ を使い、Hostヘッダーの中身が「数字とドットだけ(または末尾にポート番号)」で構成されているかを判定します。IPアドレス直打ちであれば、その瞬間に合致(マッチ)します。
  • id:10005:
    • 変数の頭に & をつけることで、そのヘッダーの「個数」を数えます。@eq 0(=0個、つまりHostヘッダーが存在しない)場合にマッチします。
  • phase:1:
    • これが非常に重要です。リクエストの解析が始まった「最速の段階(フェーズ1)」で検査を行います。
  • deny, status:404:
    • 条件にマッチしたら、荷物の中身(Body)を見るまでもなく、即座に通信を拒否し、404エラーを返して追い払います。

カスタム案が拾ったログ

以下、実際に私のサーバにアクセスしたログです。

# 例①:Hostヘッダー自体が存在しない(欠落)
[ security2:error] ModSecurity: Access denied with code 404 (phase 1). ... [file "/usr/share/modsecurity-crs/coreruleset/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf"] [line "72"] [id "10005"] [msg "[CUSTOM RULE] Missing Host Header. Blocked immediately."]

# 例②:Hostヘッダーがドメインではなく「IPアドレス直打ち」
[ security2:error] ModSecurity: Access denied with code 404 (phase 1). ... [file "/usr/share/modsecurity-crs/coreruleset/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf"] [line "63"] [id "10004"] [msg "[CUSTOM RULE] Host header is a numeric IP address (incl port). Blocked immediately."]
sequenceDiagram Note over Crawler: 不正なリクエストを送信<br>(Host: 192.0.2.1) Crawler->>ModSecurity_WAF: HTTP GET / (Host不正) Note over ModSecurity_WAF: phase:1 で瞬時に検知!<br>背後のWebサーバーやアプリには<br>一切パスさせない ModSecurity_WAF-->>Crawler: 404 Not Found (即座に遮断)

という形で、ModSecurityの背後にあるコンテンツに一切触れさせることなく追い払うことができます。

余談:これで追い返して問題は無いのか?

ありません。断言します。なぜなら、ローカル運用ならいざ知らず、ドメインで動くモダンインターネットにおいて

http://203.0.113.6

などと直打ちするケースはほぼありません。なので、IPアドレス直打ちはほぼ確実に「膨大なIPをしらみつぶしに探し回るボット」です。

そして、Webサイトを閲覧するとき、ブラウザとサーバーの間では「データの荷物」がやり取りされています。この荷物は、大きく分けると「ヘッダー(Header)」「ボディ(Body)」の2つで構成されています。

郵便に例えると、以下のようなイメージです。

  • ヘッダー(Header): 封筒の表面。「宛先」「差出人」「中身の形式」などが書かれた管理情報。
  • ボディ(Body): 封筒の中身。「実際のページデータ(HTML)」や「画像」そのもの。

普段目にするWebページは「ボディ」ですが、それを正しく届けて表示するためには、不備のない「ヘッダー(封筒の表面)」を付与するというのがブラウザの挙動です。

900番BEFOREルールである意味

そして、このファイルは「CRSが動く前に対処できる」という、MtGで言う「打ち消し呪文」のようなものとして機能します。

もし、これをRESPONSE-999-EXCLUSION-RULES-AFTER-CRS.confという「最終的に評価するルール」で書いた場合

sequenceDiagram Crawler->>ModSecurity_WAF: HTTP GET / (Host: 192.0.2.1) Note over ModSecurity_WAF: 1.900番BEFORE ルール(何もなし) -> 通過 Note over ModSecurity_WAF: 2. メインCRS審査(数千のルール) Note over ModSecurity_WAF: SQLインジェクションの検査...OK<br>XSSの検査...OK<br>(延々とノーマル審査が続く) Note over ModSecurity_WAF: 3. (AFTERルールに書いた場合) Note over ModSecurity_WAF: ここでようやくルール10004にヒット ModSecurity_WAF-->>Crawler: 404 Not Found (一応遮断はできたが...)

という流れになります。

もしクローラーが超高速で連射してきた場合、この「無駄なフルコンボ審査」のせいでModSecurity自体の処理が追いつかなくなり、サーバーのCPU使用率が100%に張り付いて、一般ユーザーのアクセスが重くなる(あるいは落ちる)という本末転倒な事態が起きます。

このカスタム案の意義

OWASP CRSは非常に優秀です。

SQLインジェクション、XSS、RCEなど、現代的な攻撃に対する膨大な知見が詰め込まれており、何も考えずに導入しても一定以上の防御力を得られます。

しかし、それはあくまで「世界中の誰にでも当てはまる最大公約数」です。

私のサーバーには私のサイト構成があり、私の利用者がおり、私の攻撃ログがあります。

だからこそ

  • このサイトではコードの投稿は許可する
  • このURLへの異常なクロールだけは絶対に許さない
  • この挙動は攻撃ではないので除外する
  • この通信はコンテンツを見る価値すらないので即座に落とす
  • 面白い相手ならハニーポットへ誘導する

という「自分だけのルール」が必要になります。そのための「私のデッキ」が900番BEFOREルールです。

CRS本体を直接編集する必要はありません。

世界中のセキュリティ専門家が更新し続けるルールセットはそのまま利用し、自分の環境だけに必要な判断を、カードを1枚追加するような感覚で差し込めます。

だから冒頭で紹介した

「カードはルールに勝つ」

という考え方が、そのままModSecurityにも当てはまるのです。

CRSという基本ルールがあり、その前に「このサイトではこうする」という例外を定義する。それだけで、自分だけのWAFが出来上がります。

私にとってREQUEST-900-EXCLUSION-RULES-BEFORE-CRS.confは、単なる設定ファイルではありません。

毎日流れてくるログを眺め、

  • 「これは900番で落とせるな」
  • 「このクローラーはハニーポット送りにしよう」
  • 「これはCRSに任せた方がいい」

そんな調整を繰り返しながらデッキをチューニングしていく場所です。Webサイトを運営する人にとって、攻撃ログは鬱陶しいものに見えるかもしれません。

しかし見方を変えれば、それは次の一枚を考えるための対戦ログでもあります。

オリジナルに手を加えない意義

また、この900番BEFOREルールを別ファイルとして管理する最大の理由は、「本家に手を入れない」ことです。

CRSは更新され続けます。

もしCRS本体を書き換えてしまうと、アップデートのたびに差分を確認し、競合を解消し、自分の修正を書き戻す必要があります。

一方、自分のデッキを900番BEFOREだけに閉じ込めておけば、CRSが更新されても自分のカードはそのまま使い続けられます。

新しいサーバーへ移行するときも、自分のデッキを1枚コピーするだけです。デッキは、一度組んで終わりではありません。

  • 新しい攻撃ログを見つけたら1枚差し替え、
  • 不要になったカードは抜き、
  • 新しい環境に合わせて調整していく。

世界中の専門家が作ったルールセットを土台に、自分のサイトで得た対戦ログから一枚ずつカードを選び、デッキを育てていく。それが私にとってのREQUEST-900-EXCLUSION-RULES-BEFORE-CRS.confです。

統率者デッキ:サイオンズ・スペルの入れ替え候補

先だって購入した統率者デッキ。この攻勢を維持したまま、更に楽しくなりそうなカードをストレージから…… というよりも、パーツ取りで他がある状態での他の構築済みから引っ張ってきました。

パーツ取りのために買っていたドクター・フー統率者デッキ「悪の支配者」から

Vislor Turlough / ヴィスラー・ターロー (3)(黒)
伝説のクリーチャー — ならず者(Rogue)
ブラック・ガーディアンとの取引 ― ヴィスラー・ターローが戦場に出たとき、あなたは「対戦相手1人はこれのコントロールを得る。」を選んでもよい。そうしたなら、そのプレイヤーがコントロールし続けているかぎり、これは使嗾される。
あなたの終了ステップの開始時に、カード1枚を引き、その後、あなたの手札にあるカードの枚数に等しい点数のライフを失う。
ドクターのコンパニオン(もう一方がドクター(Doctor)であるなら、あなたは統率者2体を使用できる。)
2/5

Wound Reflection / 傷の反射 (5)(黒)
エンチャント
各終了ステップの開始時に、各対戦相手はこのターンに自分が失ったライフの点数に等しい点数のライフを失う。(ダメージによりライフは失われる。)

Blink / まばたき (2)(青)(黒)
エンチャント — 英雄譚(Saga)
(この英雄譚(Saga)が出た際とあなたのドロー・ステップの後に、伝承(lore)カウンター1個を加える。IVの後に、生け贄に捧げる。)
I,III ― クリーチャー1体を対象とする。オーナーはそれを自分のライブラリーに加えて切り直す。その後、調査を行う。(そのプレイヤーは手掛かり(Clue)トークン1つを生成する。)
II,IV ― 先制攻撃と警戒と「対戦相手1人がクリーチャー呪文1つを唱えるたび、ターン終了時まで、このパーマネントはクリーチャーでない。」を持つ黒の2/2のエイリアン(Alien)・天使(Angel)アーティファクト・クリーチャー・トークン1体を生成する。

Hunted by The Family / ファミリーの擬態 (5)(青)(青)
ソーサリー
あなたがコントロールしていないクリーチャー最大4体を対象とする。それらの各クリーチャーにつきそれぞれ、そのコントローラーは「そのクリーチャーは白の1/1の人間(Human)クリーチャーになりすべての能力を失う。」か「あなたはそれのコピーであるトークン1つを生成する。」かの最悪の二択を行う。


同じくドクター・フー統率者デッキ『過去からの来襲』より

The Second Doctor / 2代目ドクター (2)(白)(青)
伝説のクリーチャー — タイム(Time) ロード(Lord) ドクター(Doctor)
すべてのプレイヤーの手札の上限はなくなる。
見上げた文明人 ― あなたの終了ステップの開始時に、各プレイヤーはそれぞれカード1枚を引いてもよい。次の自分のターンまで、それを行った各対戦相手はそれぞれ、あなたやあなたがコントロールしているパーマネントを攻撃できない。
2/4

Trial of a Time Lord / タイムロードの審判 (1)(白)(白)
エンチャント — 英雄譚(Saga)
(この英雄譚(Saga)が出た際とあなたのドロー・ステップの後に、伝承(lore)カウンター1個を加える。IVの後に、生け贄に捧げる。)
I,II,III ― 対戦相手がコントロールしていてトークンでないクリーチャー1体を対象とする。これが戦場を離れるまで、それを追放する。
IV ― あなたから始めて各プレイヤーは「無罪」または「有罪」のいずれかに投票する。「有罪」がより多くの票を得たなら、これにより追放されている各カードのオーナーはそれぞれ、そのカードを自分のライブラリーの一番下に置く。


更にドクター・フー統率者デッキ『タイミーワイミー』から

Grasp of Fate / 命運の掌握 (1)(白)(白)
エンチャント
命運の掌握が戦場に出たとき、対戦相手1人につき、そのプレイヤーがコントロールする土地でないパーマネントを最大1つまで対象とし、命運の掌握が戦場を離れるまでそれを追放する。(それらのパーマネントはオーナーのコントロール下で戦場に戻る。)

Wedding Ring / 結婚指輪 (2)(白)(白)
アーティファクト
結婚指輪が戦場に出たとき、これが唱えられていた場合、対戦相手1人を対象とする。そのプレイヤーはこれのコピーであるトークン1個を生成する。
《結婚指輪/Wedding Ring》という名前のアーティファクトをコントロールしている対戦相手のターンにそのプレイヤーがカード1枚を引くたび、あなたはカード1枚を引く。
《結婚指輪/Wedding Ring》という名前のアーティファクトをコントロールしている対戦相手のターンにそのプレイヤーがライフを得るたび、あなたはその点数に等しい点数のライフを得る。

このあたり、

  • 統率者の誘発を助け
  • 自分を守り
  • 政治的駆け引きも多い

防御札。ここまで自由度が高い統率者はそうそう見られないとして、カードの発見が楽しいです。

AIのトークン消費はなぜバラつくのか?――創作・分析・編集で「脳の使い方」が違うように見える話

AIを日常的に使っていると、ふとこんなことに気付きます。

  • 「この依頼は意外と利用量が増えないな」
  • 「逆に、この程度の文章なのに思った以上に消費する」

私自身、普段はGeminiを使って画像生成プロンプトの修正や競馬予想の分析、ブログの推敲、物語の執筆など、さまざまな用途でAIを利用しています。

その中で感じたのは、「依頼する内容によって利用量の増え方がかなり違う」ということでした。

もちろん、AI各社は利用量の計算方法を公開しているわけではありません。表示される消費量が単純なトークン数なのか、推論時間なのか、それらを組み合わせた独自の指標なのかは分かりません。

この記事は、あくまで私が日常的に使う中で見えてきた経験則です。

「文字数」よりも「何をさせるか」の方が重要だった

最初に不思議だと思ったのが、画像生成プロンプトです。5000文字を超える長いプロンプトを修正しても、トークンの利用量は数%程度で済むことがあります。一方で、「1000文字くらいの短い物語を書いてください」と依頼すると、それだけで10%近く増えることもありました。

文字数だけを見れば、前者の方が圧倒的に長いはずです。ところが、AIにとって重要なのは文字数ではなく、「どんな仕事を頼まれているか」なのではないか、と感じるようになりました。

ゼロから創る仕事は、とにかく重そうだ

物語を書く仕事は、AIにとってかなり負荷が高いように見えます。

  1. 登場人物を考え、
  2. 会話を自然につなぎ、
  3. 伏線を張り、
  4. 最後まで一貫性を維持する。

しかも文章は一気に完成するわけではありません。

AIは「次に来る最も自然な単語は何か」を少しずつ判断しながら、文章を積み重ねていきます。つまり、1000文字の小説を書くということは、「1000文字分の判断」を積み重ねる作業でもあります。

もちろん内部では人間のように「悩んでいる」わけではありませんが、利用量という観点では、このような創作タスクほど大きく増える傾向を私は何度も経験しました。(少なくともGeminiで可視化されている利用量を見る限り、その傾向ははっきり現れています。)

分析や編集は「答えを探す仕事」

逆に、競馬予想の分析やブログの校正、画像生成プロンプトの修正などは、それほど利用量が増えないことが多くあります。もちろん分析にも推論は必要です。

競馬であれば過去データや馬場状態、展開などを整理して結論を導かなければなりません。しかし、これは「何もないところから世界を創る」仕事ではありません。

与えられた情報を整理し、関連性を見つけ、答えを導く仕事です。画像生成プロンプトの修正も同様です。

  • 「かわいい雰囲気を少し減らして」
  • 「夕暮れを夜景に変更して」
  • 「背景をモンサンミッシェルからセントマイケルズマウントに変更して」

といった依頼では、新しい世界を創造しているのではなく、既にある設計図を編集しています。人間に例えるなら、小説を書くよりも、設計図を赤ペンで修正する仕事に近い印象があります。

文体変換は「下絵が完成している」

個人的に最も面白かったのが、文体変換です。

例えば、私がよくやっているのが

  • 「歴史的事実をニンジャスレイヤー風に書く」
  • 「ハリー・ポッターを池波正太郎風に書く」

といった依頼です。

これも一見すると創作のようですが、実際の利用量はゼロから物語を書く場合よりかなり少なく感じられました。

この理由を考えてみると、文体変換では「何が起こるか」は既に決まっています。

AIが考える必要があるのは、「どう表現するか」だけです。

これは白紙のキャンバスに絵を描く作業ではなく、完成した下絵に画風を合わせて色を塗るようなものです。物語の骨格が既に存在するため、ゼロから組み立てるよりも効率よく処理できるのではないか、と感じています。

AIにも「得意な仕事」と「重い仕事」がある

今回の観察から、私の中ではAIへの依頼は次のようなイメージになりました。

  • データ整理・分析(かなり軽い)
    • 与えられた情報を整理する仕事
  • 編集・文体変換 (軽い)
    • 内容はそのままに表現を整える仕事
  • ゼロからの創作(重い)
    • 内容そのものを組み立てる仕事

もちろん境界は曖昧ですし、実際の内部処理がこの通りだと断言することはできません。(AIの仕様そのものがブラックボックスであることは、皆様もご存じでしょう)それでも、利用量の増え方を見ていると、この順番で負荷が高くなっているように見えます。

AIを使い分けるヒント

この経験則を踏まえると、AIを効率よく使う方法も見えてきます。

  • 「物語のプロットだけは自分で考え、AIには文章を書き直してもらう」
  • 「まず箇条書きで構成を作り、そのあと文体だけ整えてもらう」

という使い方です。ゼロから創作を任せるよりも、利用量を抑えながら質の高いアウトプットを得られる場面が少なくありません。

なので「揮発性のアイデアは人間が捕まえ、形にするのはAIに任せる」やり方は相当効率的です。

おわりに

この記事は、AIの内部仕様を解説したものではありません。(そもそも筆者はAIを使うことはあっても作る技術はありません)

あくまで、一人のヘビーユーザーとして毎日のようにAIを使い続ける中で見えてきた経験則です。それでも、「文字数」ではなく「AIにどんな仕事を頼むか」で利用量が変わるように見えるという発見は、とても興味深いものでした。

AIは万能な魔法ではなく、それぞれの仕事に向き・不向きがあります。

人間が「何を考え」、AIに「何を考えてもらうか」を意識するだけでも、同じAIでも驚くほど付き合い方は変わってきます。AIの「脳の使い方」を少し意識するだけで、その能力をより引き出せるのではないでしょうか。

Page 3 of 3

Powered by WordPress & Theme by Anders Norén