Share
Embed
Transcript
36 slides
-
今日話すこと • 正規表現のおさらいとReDoSの仕組み • ReDoSの事例 • ReDoSのスキャンツールの紹介 • ReDoSの予防 •
まとめ 間違いの指摘や質問は @kawada_syogo225 までお願いします! -
連接・選択・繰り返し • 連接 ◦ 単純に隣り合う文字を表す。ただの文字列も正規表現。 ◦ 例:abcd、hogefuga、regex • 選択 ◦
並べた正規表現のどれかを選ぶ。 ◦ 例:Java(S|s)script ← JavaScript、または、Javascriptを表す。 • 繰り返し ◦ ある正規表現を繰り返し適用する。 ◦ 例:(0|1)* ← 0か1が繰り返し出現する文字列にマッチする。つまり、バイナリ。 -
文字クラス・特殊文字・キャプチャ • 文字クラス ◦ アルファベット、数字などのまとまった文字達を表す。 ◦ 例:[a-zA-Z]、[0-9]、[02468] • メタ文字 ◦
数字や非単語構成文字(記号)や行頭、行末などを表す特別な記号 ◦ 例:^\s++$ ← 空白のみで構成される行 • キャプチャ ◦ 正規表現のグループ化、演算の優先度の変更、部分的な取り出しに利用できる ◦ 例:YYYY/MM/DDをYYYY-MM-DDに変換する正規表現と JavaScriptコード。 > '2020/07/15'.replace(/(\d\d\d\d)\/(\d\d)\/(\d\d)/, '$1-$2-$3'); '2020-07-15' > -
繰り返しについてもう少し • スター演算子 ◦ 0回以上の繰り返しを表す ◦ 例:\d* ← 空文字か任意個の数字列にマッチ • プラス演算子 ◦
1回以上の繰り返しを表す ◦ 例:\d+ ← 一つの数字か任意個の数字列にマッチ • 疑問符演算子 ◦ 0回か1回の繰り返しを表す ◦ 例:\d? ← 空文字か1個の数字にマッチ • 範囲量指定子 ◦ n~m回の繰り返しを表す。( n < m) ◦ 例:\d{2,10} ← 2個以上、10個以下の数字の繰り返しにマッチ -
(欲張りな|控え目)な量指定子 • 欲張りな量指定子 ◦ 可能な限り長くマッチしようとする。「 *」、「+」、「?」、「{n,m}」が欲張る。 ◦ 例:(\d*)(\d*) ← 左のグループが全ての数字を消費する。 • 控え目な量指定子
◦ 可能な限り短くマッチしようとする。「 *?」、「+?」、「??」、「{n,m}?」が控え目。 ◦ 例:(\d*?)(\d+) ← 左のグループは控え目なため、右のグループが欲張る。 -
答え 1. 最初の「x+」が10個の(全て)の「x」にマッチする。 2. 2番目の「x+」が失敗する。 3. 最初の「x+」が「x」を一つ手放して、9個の「x」にマッチする。 4. 2番目の「x」が1個の「x」にマッチする。 5.
グループに繰り返し「+」がついているが、これ以上マッチする部分が ない為、1回のマッチで終了する。 6. 「y」が「y」とマッチする。 -
マッチ対象に「y」がなかったら? 1. 最初の「x+」が2つ「x」を手放して8つの「x」にマッチ。 2. 2番目の「x+」が2個の「x」にマッチ。 3. グループの繰り返しに失敗。 4. yのマッチに失敗。 5.
2番目の「x+」が「x」を手放して1つの「x」にマッチ。 6. グループの繰り返しに失敗。 7. yのマッチに失敗。 8. 最初の「x+」が3つの「x」を手放して8つの「x」にマッチ。 9. 2番目の「x」が3つの「x」にマッチ。 10. 以下、繰り返し。 文章で説明するとめんどい。。。 -
バックトラック • 正規表現はマッチするまであらゆる組み合わせを試行する。 • 直前の例でみたような、後戻りして再試行するような動作を バックトラックという。 • (x+x+)+ だけでもマッチ組み合わせが 大量に存在するが、その全てを
試行してもマッチすることはない。 ◦ (9,1)、(8,2)、(8,1)、(5,5)、(1,9) ◦ ((7,1),(1,1)) ◦ ((1,1),(1,1),(1,1),(1,1),(1,1)) -
Stack Overflowの例 • 2016年7月20日にReDoSで34分の停止が発生。 • 「-- play happy sound for
player to enjoy」の後に2万個のスペースが続く 投稿が原因でDoSった。 • 原因の特定に10分、コードの修正に14分、修正の適用に10分かかった らしい。。。対応、早くない?! • 行頭と行末のスペースを除去するために「^[\s\u200c]+|[\s\u200c]+$」 という正規表現を使用していた。 • https://stackstatus.net/post/147710624694/outage-postmortem-july-20-2016 -
ModSeucrity CRSの例 • ModSecurityはOWASPが提供するOSSなWAF。 • CRS(Core Rule Set)はOWASPが提供するOSSなWAFルール。 • 2019年にCRSのReDoSが5つ見つかっている。
◦ https://coreruleset.org/20190425/regular-expression-dos-weaknesses-in-crs/ -
Expressの例 • 2016年にExpress が依存する nagotiator という Accept-Language ヘッダー を扱うライブラリでReDoSが見つかった。 •
修正コミット ◦ https://medium.com/node-security/regular-expression-denial-of-service-affecting-express-js-9c397c164c43 • 以下のようなコードを書いてるとDoSる。 app.get('/', (req, res) => { if (req.acceptsLanguages ('ja')) { res.send('ピエン'); } else { res.send }); -
w3af • 右のようなReDoSを引き起こしそうな文字列を送信して RTTが通常より4倍遅くなればReDoSと判定。 • 「a」や「1」は10個ずつ増やしていき、最終的に80個 まで試す。 • ソースコードは以下。 ◦
https://github.com/andresriancho/w3af/blob/master/w3af/plugins/audit/redos.py aaaaaaaaaaX! aaaaaaaaaaaaaaaaaaaaX! aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaX! [email protected]! [email protected]! [email protected]! 11111111119! 111111111111111111119! 1111111111111111111111111111119! -
Wisdom/RegEx-DoS • esprimaというES7まで対応したJavaScriptのパーサを使って 正規表現リテラルを摘出。 • new RegExp(‘aaaa’) や動的に正規表現を組み立てている場合は 摘出できない。 •
ReDoSの判定自体は safe-regex に丸投げ。 • リポジトリ ◦ https://github.com/Wisdom/RegEx-DoS -
safe-regex • regexp-tree というライブラリを使って正規表現をASTに変換して、 ASTを再帰的に走査して、一番ネストした * 演算子を探す。 • ネストの深さが「1」以上、または、* 演算子が25個より多く
使用されている場合は危険と判定。 • 「星の高さ」という概念を基にしている。 • 例えば、(b|aa*b)*aa* の星の高さは 2 。 • 入れ子になった * 演算子は組み合わせ爆発を誘発しやすい。 • リポジトリ ◦ https://github.com/davisjam/safe-regex/ -
davisjam/vuln-regex-detector • 複数の検出器によるチェックを行い、指定した言語の正規表現エンジンにて テストを行うことで検知の精度を高めている。 • 正規表現エンジンの機能や独自の最適化によって特定のエンジンのみ処理時間が 悪化するケースがある為、このような方針を採用している。 • Githubリポジトリを指定してのスキャンが可能で、ソースコードからの正規表現の 摘出はJavaScriptとPythonしているが、動的に正規表現を組み立てている場合は
対応できない。 • 正規表現の摘出、ReDoSの検知、テストがそれぞれ別のスクリプトに なっているため、単体で利用可能。 • リポジトリ ◦ https://github.com/davisjam/vuln-regex-detector/ -
google/re2 • Googleが開発した正規表現エンジン。 • ユーザーからの信頼できない入力に対してリスクなく正規表現を扱えるよう 設計・実装されている。 • 入力された文字列に対して線形時間でマッチングを行えることを 保証している。 •
その代わりに、他の正規表現エンジンと比べて機能が制限されている。 ◦ https://github.com/google/re2/wiki/WhyRE2 • 先述のCloudflareの事例で、事後対応としてRE2の採用が上がっている。 -
ツールやエンジンのオプションを活用する • ReDoSのチェックは時間がかかるため、チェック済みの正規表現を ライブラリとして持っておくのも良いかも。 • エンジンによってはバックトラックの上限が設定できたりするので、 確認する。 • PHPは「pcre.backtrack_limit」で可能。 •
ModSecurityは「SecPcreMatchLimit/SecPcreMatchLimitRecursion」 • .NETはRegexコンストラクタの第三引数でタイムアウトを設定可能。 -
まとめ • ReDoSは正規表現のマッチングの計算量の増大により引き起こされる。 • ReDoSはビジネスロジック、ライブラリ、ミドルボックス等至る所に 潜んでいる。 • WAFでの防御ができない。むしろ、WAFが攻撃対象になる。 • 現時点では脆弱性診断が難しい。
• 予防のために、パフォーマンスに関する作法を学ぼう。 • ツールを使用して疑わしい正規表現をチェックする。 • 正規表現エンジンや言語の設定で計算リソースを制限する。 -
参考文献 • 正規表現技術入門 ー最新エンジン実装と理論的背景ー ◦ https://gihyo.jp/book/2015/978-4-7741-7270-5 • 詳説 正規表現 ◦ https://gihyo.jp/book/2015/978-4-7741-7270-5 •
正規表現入門 星の高さを求めて ◦ https://www.slideshare.net/sinya8282/ss-32629428 • Runaway Regular Expressions: Catastrophic Backtracking ◦ https://www.regular-expressions.info/catastrophic.html • The Impact of Regular Expression Denial of Service (ReDoS) in Practice ◦ https://medium.com/bugbountywriteup/introduction-987fdc4c7b0 • The Regular Expression Denial of Service (ReDoS) cheat-sheet ◦ https://levelup.gitconnected.com/the-regular-expression-denial-of-service-redos-cheat-sheet-a78d0ed7d865 • A Sense of Time for JavaScript and Node.js ◦ https://medium.com/@davisjam/a-sense-of-time-for-javascript-and-node-js-68c9114f5d48 • 正規表現とセキュリティ / Regular Expressions and Their Security-Related Aspects ◦ https://speakerdeck.com/lmt_swallow/regular-expressions-and-their-security-related-aspects