ReDOS攻撃というのが流行っているらしい。 ReDOS攻撃is何?
ユーザの入力を安易に正規表現に通すとDoS攻撃を受けることがある。
ごく単純な正規表現
/^(([a-zA-Z0-9])+)+$/
アルファベットまたは数字の繰り返しにマッチし、マッチした部分を返す。
とりあえず3.1.0で試す。
irb(main):013:0> RUBY_VERSION
=> "3.1.0"
irb(main):002:0> 'abcde'.match(re).to_s
=> "abcde"
irb(main):003:0> '1234567'.match(re).to_s
=> "1234567"
一瞬で返る。
irb(main):004:0> 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'.match(re).to_s
=> "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
これも瞬時に返る。
irb(main):007:0> 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@'.match(re).to_s
フリーズする! (実際には非常に時間がかかるだけ)
正規表現がどのようにマッチングをしているか考える必要がある。
このサイトで正規表現をチェックできる。
最後の@まで行ってから戻る、@まで進む、また一つ戻る、@まで進む・・・の繰り返し(バックトラック)が発生するため。
攻撃者はある程度の長さを持ち、バックトラックを発生させる正規表現を検索フォーム等に流すだけでプロセスを長時間占有することができる。 それを多数同時にやればいとも簡単にDoS攻撃ができてしまう。
URLやメールアドレスのマッチ等は処理系で定義済みのものや公開されているものを使う。 自分で下手に書くとリスクがある。
irb(main):001:0> RUBY_VERSION
=> "3.2.2"
irb(main):002:0> 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@'
.match(re).to_s
=> ""
ruby3.2だとアルゴリズムが改善されているため、そもそもこの正規表現でもフリーズせず一瞬で返る。
*や+など無制限の繰り返しを含む正規表現を書かない。
例えば上の例なら /^(([a-zA-Z0-9]){,10}){,10}$/ のようにすれば繰り返し回数を制限できる。
最近の処理系では正規表現のタイムアウトを設定できる。 例えば1000msとかにしておけばフリーズは避けられる。 ちなみにrubyだと・・・
https://zenn.dev/tmtms/articles/202212-ruby32-12 https://bugs.ruby-lang.org/issues/17837
3.2から入ってます。