なぜ邪悪な正規表現が問題なのですか?
コンピュータは、たとえそれがあなたが意図したものではなく、まったく不合理であっても、あなたが彼らに指示したことを正確に行うからです。正規表現エンジンに、特定の入力について、特定のパターンに一致するものと一致しないものがあることを証明するように依頼すると、エンジンは、テストする必要のあるさまざまな組み合わせの数に関係なく、それを実行しようとします。
これは、OPの投稿の最初の例に触発された単純なパターンです。
^((ab)*)+$
与えられた入力:
abababababababababababab
正規表現エンジンは次のようなこと(abababababababababababab)
を試行し、最初の試行で一致が見つかります。
しかし、次にモンキーレンチを投入します。
abababababababababababab a
エンジンは最初に試行(abababababababababababab)
しますが、その余分なために失敗しますa
。これは壊滅的なブラックトラッキングを引き起こします。なぜなら、私たちのパターンは(ab)*
、誠意を持って、キャプチャの1つを解放し(「バックトラック」し)、外側のパターンを再試行させるからです。正規表現エンジンの場合、次のようになります。
(abababababababababababab)
-いいえ
(ababababababababababab)(ab)
-いいえ
(abababababababababab)(abab)
-いいえ
(abababababababababab)(ab)(ab)
-いいえ
(ababababababababab)(ababab)
-いいえ
(ababababababababab)(abab)(ab)
-いいえ
(ababababababababab)(ab)(abab)
-いいえ
(ababababababababab)(ab)(ab)(ab)
-いいえ
(abababababababab)(abababab)
-いいえ
(abababababababab)(ababab)(ab)
-いいえ
(abababababababab)(abab)(abab)
-いいえ
(abababababababab)(abab)(ab)(ab)
-いいえ
(abababababababab)(ab)(ababab)
-いいえ
(abababababababab)(ab)(abab)(ab)
-いいえ
(abababababababab)(ab)(ab)(abab)
-いいえ
(abababababababab)(ab)(ab)(ab)(ab)
-いいえ
(ababababababab)(ababababab)
-いいえ
(ababababababab)(abababab)(ab)
-いいえ
(ababababababab)(ababab)(abab)
-いいえ
(ababababababab)(ababab)(ab)(ab)
-いいえ
(ababababababab)(abab)(abab)(ab)
-いいえ
(ababababababab)(abab)(ab)(abab)
-いいえ
(ababababababab)(abab)(ab)(ab)(ab)
-いいえ
(ababababababab)(ab)(abababab)
-いいえ
(ababababababab)(ab)(ababab)(ab)
-いいえ-いいえ-いいえ-いいえ-いいえ-いいえ-いいえ
(ababababababab)(ab)(abab)(abab)
-いや
(ababababababab)(ab)(abab)(ab)(ab)
-いや
(ababababababab)(ab)(ab)(ababab)
-いや
(ababababababab)(ab)(ab)(abab)(ab)
-いや
(ababababababab)(ab)(ab)(ab)(abab)
-いや
(ababababababab)(ab)(ab)(ab)(ab)(ab)
-いや
...
(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(abababab)
-いや
(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ababab)(ab)
-いや
(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(abab)(abab)
-いや
(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(abab)(ab)(ab)
-いや
(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ababab)
-いや
(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(abab)(ab)
-いや
(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(abab)
-いや
(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)
-いや
可能な組み合わせの数は入力の長さに応じて指数関数的に増加し、正規表現エンジンは、考えられるすべての用語の組み合わせを使い果たして最終的にあきらめるまで、この問題を解決しようとしてすべてのシステムリソースを使い果たします。 「一致するものはありません」と報告します。その間、サーバーは溶けた金属の燃える山に変わりました。
邪悪な正規表現を見つける方法
それは実際には非常にトリッキーです。私はそれらが何であるか、そして一般的にそれらを避ける方法を知っていますが、私は自分でカップルを書きました。驚くほど長い時間がかかる正規表現を参照してください。アトミックグループで可能なすべてをラップすると、バックトラックの問題を防ぐのに役立ちます。これは基本的に、正規表現エンジンに、指定された式に再度アクセスしないように指示します。「最初の試行で一致したものはすべてロックします」。注意は、しかし、原子式はバックトラックを妨げないことの中に表現なので、^(?>((ab)*)+)$
まだ危険ですが、^(?>(ab)*)+$
(それが一致するよ安全です(abababababababababababab)
し、それがこのように壊滅的なバックトラッキングを防ぐ、文字にマッチしていますのいずれかを放棄することを拒否します)。
残念ながら、一度作成すると、問題の正規表現をすぐにまたはすばやく見つけることは実際には非常に困難です。結局のところ、悪い正規表現を認識することは、他の悪いコードを認識することと同じです。多くの時間と経験、および/または単一の壊滅的なイベントが必要です。
興味深いことに、この回答が最初に書かれて以来、テキサス大学オースティン校のチームは、これらの「邪悪な」パターンを見つけるという明確な目的で正規表現の静的分析を実行できるツールの開発について説明した論文を発表しました。このツールはJavaプログラムを分析するために開発されましたが、特にReDoS攻撃の割合が増え続けるにつれて、JavaScriptやその他の言語で問題のあるパターンを分析および検出するために開発されるツールが今後さらに増えると思います。
正規表現を使用するプログラムでのDoS脆弱性の静的検出
ValentinWüstholz、Oswaldo Olivo、Marijn JH Heule、およびIsilDillig
テキサス大学オースティン校