WAF
Web Application Firewall ・ ワフ
HTTPリクエストの中身を検査して攻撃のパターンを遮断する、アプリの手前の防御層。
✦ 30秒で試す — 航海門番を厳しくするほど、普通のお客まで締め出されるこの要求を、WAF のルールで止められる?予想してみる概要
WAF(Web Application Firewall)は、Web アプリケーションの手前に立ち、届いた HTTP リクエストの中身を検査して、攻撃とみなしたものを遮断する防壁です。URL やヘッダ、クエリパラメータ、POST のボディまで開いて、「このパラメータに SQL の断片が混ざっていないか」「スクリプトタグが仕込まれていないか」といったアプリケーション層の観点で判定するのが特徴です。SQLインジェクションやXSSのように、アプリの実装の隙を突く攻撃への防御層として使われます。
名前に「ファイアウォール」とありますが、従来のファイアウォールとは見ている層が違います。従来型(ネットワークファイアウォール)は OSI参照モデルでいう L3/L4、つまりIPアドレスとポート番号を見て「どこからどこへの通信を通すか」を判断します。しかし Web サービスは 443 番ポートを全世界に開けて成り立つものなので、攻撃も正規のアクセスも同じ港から入ってきます。L7(アプリケーション層)でリクエストの中身まで読まなければ区別できない。その役割を担うのが WAF です。
なぜ生まれたか
2000年代、Web アプリケーションが爆発的に増えると、攻撃の主戦場はネットワークからアプリケーションの実装へ移りました。SQLインジェクションもXSSも、プロトコルの上では完全に正当な HTTP リクエストであり、IPアドレスとポートしか見ないファイアウォールは素通しです。本来の対策はアプリのコードを直すことですが、現実には「脆弱性は見つかったが、修正のリリースまで数週間かかる」「保守の終わった古いシステムやパッケージ製品で、そもそもコードに手を入れられない」という状況が至るところにありました。
コードを直せるまでの間、既知の攻撃パターンだけでも手前で堰き止められないか。この需要に応えて、HTTP を理解して中身を検査する専用の防壁として WAF が生まれました。オープンソースの ModSecurity(2002年〜)がその代表で、Apache の拡張として動きながら、リクエストを規則の集まりと照合して止める方式を広めました。
普及を後押ししたのが、クレジットカード業界のセキュリティ基準 PCI DSS です。v3.2.1 までの要件 6.6 は、公開 Web アプリに対して「脆弱性の見直し(コードレビューや診断)」か「WAF の設置」のどちらかを求めていました。2022年の v4.0 では要件 6.4.2 として、公開 Web アプリの前に「Web への攻撃を自動で検知して止める技術的な対策」(WAF がその代表)を置くことが、2025年3月末から必須になりました。いまではクラウド事業者や CDN 事業者がマネージドサービスとして提供する、Web 公開の標準装備になっています。
詳細
判定の仕組み — シグネチャとルール
WAF の中核は検知ルールです。古典的で今も主流なのが、シグネチャ(既知の攻撃パターン)の方式で、「SQL の構文の断片」「ディレクトリトラバーサルに特有の文字列」「スクリプト注入の典型形」といったパターンの集まりとリクエストを照合します。事実上の標準のルールセットが OWASP CRS(Core Rule Set)で、OWASP Top 10 に挙がる主要な攻撃を広く押さえ、ModSecurity 系のエンジンや各クラウドのマネージド WAF で使われています。
CRS は、1つのルールに一致したら即遮断するのではなく、一致したルールごとに点数を足していき、合計が閾値を超えたら遮断する異常スコアリングを採っています。単独では弱い兆候を積み上げて判定することで、誤検知を抑えつつ攻撃を捕まえるための工夫です。これに、IPアドレスのレピュテーション(攻撃元として知られたアドレスからのアクセスを止める)、ボット判定、機械学習でふだんのトラフィックからの逸脱を見つける方式などが組み合わさり、レート制限の機能を同梱する製品も一般的です。
照合の前には、正規化という大切な処理があります。攻撃者は ' を %27 と書くような URL エンコードや、文字コードの変換、大文字と小文字の混在で、ルールの文字列と一致しない形に攻撃を変形させます。アプリは受け取った値をデコードしてから使うので、WAF もアプリと同じ形に戻してから検査しないと、変形した攻撃は素通りします。WAF をすり抜ける手口(WAF バイパス)の多くは、この「WAF が見ている形」と「アプリが解釈する形」のずれを突くものです。
どこに置くか — 配置の型
WAF は、通すべきトラフィックの通り道に置く必要があるため、配置はリバースプロキシの考え方と地続きです。代表的な型は3つあります。アプライアンス/ソフトウェア型は、自前のネットワークの中でリバースプロキシとして(あるいは Web サーバのモジュールとして)動かす形です。クラウド/CDN 統合型は、DNS の向き先を事業者のエッジに切り替えるだけで、世界中に分散した CDN の入口で WAF の検査を受けられる形で、現在の主流です。エッジで攻撃を落とせるので自社のインフラに負荷が届かず、DDoS攻撃への対策と一体で提供されることが多いのも利点です。なお、WAF が中身を検査するには TLS をいったん終端して復号する必要があるため、WAF は HTTPS の終端点(またはその内側)に置かれます。
運用の主戦場 — 誤検知と見逃しの綱引き
WAF 運用の最大の難所は誤検知(false positive)、つまり正当なリクエストを攻撃と誤って判定して遮断してしまうことです。ルールは「攻撃によく現れるパターン」を見ているだけなので、SQL について質問する掲示板の投稿、コード片を含む問い合わせ、JSON に混ざる記号列などが平気で引っかかります。誤検知はそのまま利用者にとっての障害です。放置すれば「WAF のせいで正規の機能が壊れる」ことになり、逆に怖がってルールを緩めすぎれば見逃し(false negative)が増えます。この綱引きが WAF 運用の本質です。
下の部品で、ルールの札を差したり抜いたりしてみてください。「SQL の単語」のような広いルールは攻撃も止めますが正規の投稿も止め、デコードを差さなければエンコードした攻撃がすり抜けます。紫の粒(他人の注文番号を見るリクエスト)は、どの札を差しても止まりません。
左からリクエストが流れてきます。粒の色は本当の正体(青緑=正規、朱=攻撃)ですが、WAF に見えるのは中身の文字列だけです。いまは「SQLの単語」「引用符」の2枚が差さっています。下の札をタップして差したり抜いたりして、誤検知と見逃しがどう動くかを見てください。
実務の定石は、まず監視(ディテクション)モードで一定期間流すことです。遮断はせずに「止めていたら止まったもの」をログに記録し、自サイトの正常なトラフィックに合わないルールへ除外設定(特定のパスの特定のパラメータだけ検査を外す、など)をしてから、ブロックモードに切り替えます。導入して終わりの置き物ではなく、アプリの変更のたびに新しい誤検知が生まれうる、継続的な運用の対象だと考えておく必要があります。
WAF は万能ではない — 位置づけを間違えない
最後に、最も大切な位置づけの話です。WAF はパターンに一致する既知の攻撃を落とす装置であって、アプリケーションの脆弱性そのものを消すわけではありません。エンコードの工夫などでルールをすり抜ける攻撃は常に研究されていますし、認可の不備(他人の注文番号を指定する、など)やビジネスロジックの欠陥のように「リクエスト単体はどこまでも正常に見える」種類の脆弱性は、原理的に WAF では守れません。
したがって本筋はあくまでアプリ側の修正、つまりプレースホルダによる SQL の組み立て、出力のエスケープ、CSP のようなブラウザ側の防御層です。WAF の正しい役割は「修正が届くまでの時間稼ぎ」と「多層防御の一層」です。脆弱性が公表されてからパッチを当てるまでの窓を、該当する攻撃だけを狙い撃ちで止めるルール(仮想パッチ)で塞ぐ使い方は、まさに WAF の真骨頂です。2021年末に Java のログ出力ライブラリ Log4j の脆弱性(Log4Shell)が公表されたときには、多くの組織が ${jndi: を含むリクエストを止めるルールを WAF に入れて、ライブラリを更新するまでの時間を稼ぎました。「WAF を入れたから安全」ではなく「WAF があるから、直すまでの間も戦える」と捉えるのが、防御側としての正しい距離感です。
試問
画面の左から HTTP リクエストの粒が流れてきて、中央の WAF(アプリの手前で中身の文字列を調べる門番)で検査されます。粒の色は本当の正体(青緑=正規、朱=攻撃、破線の輪=エンコードで形を変えた攻撃、紫=単体では正常に見える悪用)ですが、WAF に見えるのは文字列だけです。下のルールの札をタップすると WAF に差したり抜いたりでき、いまは「SQLの単語」「引用符」の2枚が差さっています。
左からリクエストが流れてきます。粒の色は本当の正体(青緑=正規、朱=攻撃)ですが、WAF に見えるのは中身の文字列だけです。いまは「SQLの単語」「引用符」の2枚が差さっています。下の札をタップして差したり抜いたりして、誤検知と見逃しがどう動くかを見てください。
