正規表現ベースのソリューションの退化
「問題に直面した際、『正規表現を使えばいい』と考える人がいます。しかし、それによって問題が倍に増えます」 – Jamie Zawinski 氏
正規表現は、特定のパターンやトークンのシーケンス (通常テキスト) を照合する方法を記述する簡潔な方法です。しかし、テキストのシーケンスを照合する手法は、マルウェアや Web アプリケーションに対する攻撃の検出におい て、本当に効果的なアプローチなのでしょうか? より正確に言えば、どのようなタイプの Web アプリ攻撃に対して正規表現 (regex) を使ったアプローチは効果的なのでしょうか? 効果の出ないものに固執して現状に屈服したり、セキュリティ対策の効果が妨害されたりするようなことがあってはなりません。
正規表現は、経験の浅い攻撃者が好むコピーアンドペーストを使った攻撃に対しては効果があります。このような攻撃者は、他の誰かが作った攻撃方法を使用しているだけなので、攻撃の仕組みを理解していません。「アマチュア攻撃者」は他人が作ったものを単に動作可能な状態にし、Shodan などのツールを通じてインターネット上を徘徊し、攻撃を行っています。正規表現の効果は、このようなシンプルな攻撃に限られています。
攻撃の再利用可能な部分を作成する攻撃者は、その部分に変更を加えることで、正規表現を使用する単純なパターンマッチングのメカニズムを回避できることを知っています。実際、トークンの正確なシーケンスはそれほど意味がなく、重要なのはこれらのトークンの完全な表現です。
つまり攻撃の動作、時空で攻撃がどのように展開されるかということです。特定の部分やテキストは、攻撃のメカニズムを説明するというより、実装の詳細の一部に過ぎません。
現実世界の例で考えてみましょう。壁から取り外されたテレビを想像してみて ください。使用したドライバーの詳しい種類を知ることは重要でしょうか? テレビを盗もうとした泥棒ではなく、私たちがテレビの高さを調節しようとしてドライバーを使用したのかもしれません。しかし、リビングの窓が割られ、誰かがテレビを壁から取り外したとしたら、この行為に悪意があることが見て取れます。
基本的に、同じパターンのテキストでも、異なる状況では異なる意味を持ち、異なる結果を生み出します。つまり、コンテキストが重要であるということです。ブログ記事にある SQL インジェクション (SQLi) エクスプロイトのテキスト記述は、そのブログのホストに対して SQLi 攻撃を仕掛けるものとは大きく異なります。両方とも、この攻撃タイプ特有のテキストパターンを含みますが、本物の攻撃を意味するのはひとつのインスタンスのみです。
これは、正規表現がいかなる場合でも役に立たないということでは決してありません。慣用的で比較的判読しやすい正規表現は、パターンマッチングにおいて使いやすい表現です。問題は、クエリパラメーターのテキストや POST 本文のフィールドのようなトークンをパターンマッチングする手法では、最も初歩的なタイプの攻撃しか検出できないということです。Web アプリケーション以外の世界でも同じことが言えます。特定のファイルハッシュの正規表現を使用する場合、そのようなシンプルな検出方法を避けるためにファイルを化けさせる努力を怠るほど攻撃者にやる気がなく不注意であることを想定しています。そういう場合も ありますが、ほとんどの場合、そうではありません。
正確さの問題を別にしても、正規表現の使用は防御側に多大なオーバーヘッドを要求します。正規表現は柔軟性がなく、扱いづらい上、管理が困難なことが多く、特により多くのコンテキストを取り入れたい場合に適していません。例えば、コマンドインジェクションを検出するために有効な Linux/Windows コマンドをキャプチャしようとしても判読できず、不可能ではないとしても正規表現ではうまくいかないでしょう。SQLi でも同じことが言えます。結果として得られるパターンは人間には判読不可能なため、維持できません (正規表現の文法を構築しても無理です)。
メールアドレスを検証する以下の「シンプル」な正規表現をご覧ください。
`(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])`
ご自身の目で楽しく解析できますか?それとも少し雑 然としすぎていると感じますか?
ソース画像
新しい、または巧妙化する攻撃のテクニックやパターンに追い付こうとすると、必要になるオーバーヘッド (時間や労力、カフェインなど) が増えるため、アップデートの頻度が低くなり、ソリューションの有効性も衰えます。また、特に最適化するのが困難な複雑な表現を扱う場合、正規表現は多大な時間とリソースを要することがあります。人的オーバーヘッドでもパフォーマンス上のオーバーヘッドでも、攻撃の検出における正規表現の ROI は割に合わない場合が多いのです。
正規表現を使用するソリューションは多く存在しますが、攻撃の検出には向いていません。多くのセキュリティベンダーは、このことを購入者に知られたくありません。イノベーションに投資するよりも既存のテクノロジーを維持する方が、コストがずっと少なくて済むためです。しかし正規表現は、攻撃者をひるませることもなければ、攻撃にかかるコストを高めることもありません。
HTTP リクエストの解析などの手法は、より節約的 な投資の選択肢と言えます。防御側はこのような手法を採用することで、より多くのコンテキストを考慮した攻撃動作のパターンマッチングへと移行し、人やマシンによる必要な労力を軽減できます。攻撃の「動作」を細かく分析することで、新たな脆弱性が出現するたびに (頻繁に起こります) 新しいルールを設定することなく、基本的な攻撃とより巧妙な攻撃の両方 (さらにそれらの亜種) を検出できるようになります。攻撃のコンテキストと、リクエストがランタイムでどのように処理されているかを確認することで、正規表現に頼るよりも、さらに正確な判断が可能になります。
つまり今日の市場には、ゆがみが生じているということです。正規表現は今日の脅威に対応するには不適切であるにもかかわらず、セキュリティソリューションを購入する企業が求める Web アプリのセキュリティ製品のチェックリストには、いまだに「正規表現のマッチング」が主な機能のひとつとして含まれています。ほとんどのベンダーのセキュリティ製品が正規表現に依存し、他により優れたソリューションが市場に存在しなかった頃には、このような要件は適切であったと言えるでしょう。しかし、そのような時代はもう終わりました。
Better security without regex. Learn how Fastly signals give you better visibility for decisioning.
Learn more役に立たないものは排除してチェックリストを修正する
分かりやすくするために、次のシーンを想像してみてください。お客様が車の販売代理店を訪れ、車に遮眼帯 (馬具の一種) が備え付けられているか尋ねます。
戸惑った店員は「いいえ、車に遮眼帯は必要ありません」と答えます。お客様はチェックリストを確認しながら不満げに首を振ります。
そして、「ムチはあるか?」と尋ねます。
「ムチも必要ありません。ムチで打つようなことはもうしません」と店員は答えます。
「まさか馬具や馬勒まで無いなんて言うんじゃないだろうな」
「その通りです。私たちが販売しているのは車です」 店員はため息をつきながら鼻筋をつまみ、「具体的に何をする必要があるのですか?」と尋ねます。
「急いで A 地点から B 地点に移動すること」と、お客様はきっぱりと答えます。
「分かりました。その目的には車の方が馬車よりずっと向いています。自動車がこのように設計されているのには、明確な理由があるのです。それは、お客様の生活の向上に役立つイノベーションと呼ばれるものです」
「でもこれらの機能が欠けているじゃないか!」
この例は明らかにばかげていますが、今日のサイバーセキュリティの世界では、似たような会話が行われています。購入者側として、馴染みのある機能リストに執着したい理由も理解できます。馬車を購入する場合は、遮眼帯やムチ、馬勒に関して質問することは非常に賢明であると言えます。しかし、チェックリストというものは本質的に固定されていて、過去の遺物に私たちを縛り付ける傾向があります。
私たちは巧妙化し続ける高速な攻撃を嘆きながら、ひと昔前だったら技術的にまあまあ通じた時代遅れの機能をベースにしたセキュリティ製品をいまだに選択しがちです。攻撃者はさまざまな選択肢を検討し、目的を達成するのに最適なツールをその中から選びます。防御側も同じようにすべきです。唯一のオプションというわけではありませんが、リクエストパラメーターを解析するといった、より新しく熟慮された防御テクニックを検討することができます。この方法では、ランタイムでのリクエストの処理結果を分析することで、より高速かつ精度が高く、柔軟性のある脅威の検出が可能です。
問題に対する自らの思考モデルが間違っている、または時代遅れであると認識するのは気分の良いものではありませんが、非常に多くのリソースを最終的に効果の無いこれらの古いソリューションにつぎ込んできたとしても、現実は私たちが考えているよりも素早く進化しています。そして、こうした古い固執や、疑問視されない思い込みに、攻撃者は付け込むのです。攻撃の先手を打つという目標を達成するには、正規表現を超えてより先進的な検出技術へとセキュリティソリューションを進化させる必要があります。
正規表現から卒業し、解析技術を使ったより先進的なセキュリティソリューションへの移行をサポートする Fastly の取り組みについては、SmartParse 検出に関するデータシート、または解析技術を利用して Log4Shell 攻撃をブロックする方法をご紹介したブログ記事をご覧ください。SmartParse がどのように機能するかご興味のある方は、ぜひデモをリクエストしてください。