正規表現によるサービス拒否

正規表現によるサービス拒否(ReDoS)

説明

正規表現によるサービス拒否(ReDoS)は、細工された入力によってマッチングの計算量が増大し、サーバーのリソースを消費する攻撃です。入力の処理に時間がかかり、サービスを提供できなくなるおそれがあります。必ずしも無限ループが発生するわけではありません。

想定される影響

  • サービス拒否: リソースが枯渇し、通常のリクエストを処理できなくなる可能性があります。
  • 性能低下: マッチングに時間がかかり、ユーザーへの応答が遅れるおそれがあります。
  • リソースの枯渇: CPUやメモリの消費が増え、ほかの処理に影響する可能性があります。

対処方法

  • 正規表現を見直し、単純で効率的な構造にしてください。
  • エンジンが対応している場合は、マッチングにタイムアウトを設定してください。Python標準のreにはマッチングのタイムアウト引数がありません。
  • マッチング前に入力の長さを制限し、入れ子の繰り返しなど、過剰なバックトラッキングを引き起こすパターンを単純化してください。

例

最初の例は、長い入力の処理に非常に長い時間がかかる可能性があります。変更後のタイムアウトは実行時間を制限する補助策であり、非効率なパターン自体を単純化するものではありません。

変更前

python
# 処理に時間がかかる正規表現
import re

pattern = re.compile(r'(a+)+$')
test_string = 'a' * 10000 + '!'
if pattern.match(test_string):
    print("Match found")
else:
    print("No match")

変更後

python
# タイムアウトを設定した正規表現
import regex

# マッチング呼び出しに時間制限を適用
pattern = regex.compile(r'(a+)+$')
test_string = 'a' * 10000 + '!'
try:
    if pattern.match(test_string, timeout=1):
        print("Match found")
    else:
        print("No match")
except TimeoutError:
    print("Regex match timed out")

説明:

  • 変更前: 入れ子の繰り返しが、ほぼ一致する入力に対して過剰なバックトラッキングを引き起こし、処理を遅らせるおそれがあります。
  • 変更後: regexのマッチング呼び出しに秒単位のtimeoutを渡し、時間を超えた場合は組み込みのTimeoutErrorを処理します。

参考資料