ルール
ガード 遅れを防ぐ 遅い 正規表現 正規表現
正規 正規表現 を ネストされた 量化子 または
あいまいな パターン は 引き起こす 壊滅的な
バックトラック と パフォーマンスの問題 の問題を引き起こします。
対応言語 45+はじめに
正規表現は適切な入力があれば、アプリケーションを数秒から数分間フリーズさせることができる。正規表現エンジンがパターンにマッチしようとして指数関数的に増加するパスを探索すると、破滅的なバックトラックが発生する。以下のような正規表現は (イ+ロ 攻撃者は、正規表現サービス拒否(ReDoS)攻撃によってこれを悪用し、リクエストのタイムアウトが発生するかプロセスがクラッシュするまで、正規表現エンジンに100%のCPUを消費させるように細工した入力を送信する。
なぜそれが重要なのか
セキュリティへの影響(ReDoS攻撃):攻撃者は細工した入力を含む単一のリクエストでアプリケーションを麻痺させることができます。電子メールの検証や URL の解析パターンが一般的なターゲットです。帯域幅を必要とする従来の DoS 攻撃とは異なり、ReDoS は小さなペイロードしか必要としません。
パフォーマンスの低下:通常のユーザー入力は、致命的なバックトラックを引き起こし、レスポンスタイムをミリ秒から数秒に急増させる可能性がある。これは、特定の入力パターンでのみ発生するため、デバッグが困難な予測不可能な遅延を引き起こします。
プロダクション・インシデント:脆弱な正規表現がNode.jsのイベントループをブロックしたり、スレッドプールのリソースを消費したりする。リクエストが積み重なるとメモリが増加し、システムが応答しなくなる。マイクロサービスでは、1つの脆弱な正規表現が依存するサービスに障害を連鎖させる。
検出の難しさ:テストでは短い入力でうまくいくパターンも、長い入力では指数関数的に遅くなる。本番稼動まで脆弱性に気づかないことが多く、インシデント発生時に緊急展開が必要になる。
コード例
非準拠:
function validateEmail(email) {
const regex = /^([a-zA-Z0-9_\-\.]+)+@([a-zA-Z0-9_\-\.]+)+\.([a-zA-Z]{2,5})$/;
return regex.test(email);
}
function extractURLs(text) {
const regex = /(https?:\/\/)?([\w\-])+\.(\w+)+([\w\-\.,@?^=%&:/~\+#]*)+/g;
return text.match(regex);
}
なぜ危険なのか: 入れ子になった量化子 ([a-zA-Z0-9_\\-\\.]+)+ 指数関数的なバックトラックが発生する。次のようなメールの場合 ああああああああああああああああ!正規表現エンジンは、失敗する前に無数の組み合わせを試す。URL正規表現には複数の入れ子になった量化子があり、これが問題を複雑にしているため、期待された構造を持たない有効な文字の長い文字列のような入力では、簡単に悪用されてしまう。
✅ 準拠:
function validateEmail(email) {
const regex = /^[a-zA-Z0-9_\-\.]+@[a-zA-Z0-9_\-\.]+\.[a-zA-Z]{2,5}$/;
return regex.test(email);
}
function extractURLs(text) {
const regex = /https?:\/\/[\w\-]+\.[\w\-]+(?:[\w\-\.,@?^=%&:/~\+#]*)?/g;
return text.match(regex);
}
なぜ安全なのか:入れ子になった量化子を削除することで、破滅的なバックトラックがなくなる。a-zA-Z0-9_-.]+のような単一の量化子は線形時間で実行される。URLパターンは、ネストされた繰り返しの代わりに、オプションの接尾辞(?:...)を持つキャプチャしないグループを使用し、入力の長さや内容に関係なく予測可能なパフォーマンスを保証します。
結論
正規表現の性能は、単なる最適化ではなく、セキュリティ上の懸念事項である。すべての正規表現パターンについて、入れ子になった量化子、繰り返しグループ内の重複する文字クラス、あいまいな選択肢についてレビューする。正規表現パターンを病理学的な入力(有効な文字の長い文字列の後に無効な末尾が続く)でテストし、配備前に致命的なバックトラックを特定する。可能であれば、複雑な正規表現を、予測可能な性能特性を持つ文字列解析関数に置き換える。
.avif)
