preg_replaceが危険ということについて。


http://blog.64p.org/entry/2013/07/17/151532
こちらで、気になる表現があり、
「基本的に、任意のユーザー入力を正規表現として評価することはさけなければなりません。」
と書かれていました。

これは、 preg_matchでも同様に、ユーザー入力を正規表現でそのまま評価することは、避けるべきものでしょうか?

もしそうであれば、ユーザが入力した文字列を「英数字のみかどうか」等、バリデートする場合、どのように判定することが安全でしょうか?

何か見逃しがあると困るので、質問しました。

アドバイス頂けると助かります。

回答の条件
  • 1人5回まで
  • 登録:
  • 終了:2013/07/24 21:55:04
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:a-kuma3 No.2

回答回数4973ベストアンサー獲得回数2154

ポイント33pt

これは、 preg_matchでも同様に、ユーザー入力を正規表現でそのまま評価することは、避けるべきものでしょうか?

質問で示されているブログで言及されているのは、preg_replace の e 修飾子がやべえって話です。

e (PREG_REPLACE_EVAL)

この修飾子を設定すると、 preg_replace() は、置換文字列において後方参照に関する通常の置換を行った後、 PHP コードとして評価し、検索文字列を置換するためにその結果を 使用します。 置換された後方参照においては、 単引用符や二重引用符、バックスラッシュ (\)および NULL 文字は バックスラッシュでエスケープされます。

http://www.php.net/manual/ja/reference.pcre.pattern.modifiers.php

preg_replace() の第二引数に書かれたコードを実行してしまう、というのが、相当にやばい。
# これについては、了解済み?



で、入力したデータをそのまま正規表現として扱う場合の話。

任意のユーザー入力をそのまま正規表現としてうけとると、容易に DoS(Denial of Service) が可能となるということはよく知られている事実であるから、任意のユーザー文字列を正規表現としてうけとっている時点で脆弱なサーバー実装になっている。

http://blog.64p.org/entry/2013/07/17/151532

当のブログの他の記事を見ても、どこまで分かって書いてるのか、(ぼくには)よく分からないのですけれど、多分、この辺りのことを書いているのだと思います。
http://msdn.microsoft.com/ja-jp/magazine/ff646973.aspx
http://www.hpenterprisesecurity.com/vulncat/ja/vulncat/objc/denial_of_service_regex_evaluation.html

これを気にするなら、置換が無い preg_match() も脆弱性に該当します。
サニタイズはちょっと難しいですけど、バリデーションという意味なら、グルーピングの表現をはじいてあげる感じになると思います。

if (preg_match('/[^\\\\]\(/', $input)) {
    グルーピングの表現がある!
}
id:onigirin

どうもありがとうございます。
第2引数のことは了解済みです。

脆弱性の方も、参照URLで理解できました。
どの正規表現でも問題があるなら、とりあえずグループ表現をはじくと、こちらの対策はできそうということで、対策法がわかり安心しました。

いろいろなサイトやスクリプトのコードを見ていると、この対策がされていないような気もするのですが、ひとつDOS対策の知識が増えて助かりました。

2013/07/19 20:11:13

その他の回答2件)

id:dawakaki No.1

回答回数797ベストアンサー獲得回数122

ポイント34pt

そのブログでは、preg_replaceの第1引数(正規表現パターン)にユーザー入力を入れるのは避けた方がいいと書いてあるのであって、第2引数(比較文字列)に入れる分には問題ありません。
preg_matchでも同様ですし、その他、たとえばSQL関数でもSQL文としてにユーザー入力を入れるのは避けるのが定石です。
これはPHPに限ったことではありません。

「英数字のみかどうか」等、バリデートする方法は、第1引数を固定文字列にすればいいです。

preg_match('/^[a-z|A-Z]+$/', $text);
id:onigirin

どうもありがとうございます。

第2引数であれば、とりあえず問題無いのは安心しました。

No2の方の情報から、気になっている危険性もわかってきました。

2013/07/19 20:04:17
id:a-kuma3 No.2

回答回数4973ベストアンサー獲得回数2154ここでベストアンサー

ポイント33pt

これは、 preg_matchでも同様に、ユーザー入力を正規表現でそのまま評価することは、避けるべきものでしょうか?

質問で示されているブログで言及されているのは、preg_replace の e 修飾子がやべえって話です。

e (PREG_REPLACE_EVAL)

この修飾子を設定すると、 preg_replace() は、置換文字列において後方参照に関する通常の置換を行った後、 PHP コードとして評価し、検索文字列を置換するためにその結果を 使用します。 置換された後方参照においては、 単引用符や二重引用符、バックスラッシュ (\)および NULL 文字は バックスラッシュでエスケープされます。

http://www.php.net/manual/ja/reference.pcre.pattern.modifiers.php

preg_replace() の第二引数に書かれたコードを実行してしまう、というのが、相当にやばい。
# これについては、了解済み?



で、入力したデータをそのまま正規表現として扱う場合の話。

任意のユーザー入力をそのまま正規表現としてうけとると、容易に DoS(Denial of Service) が可能となるということはよく知られている事実であるから、任意のユーザー文字列を正規表現としてうけとっている時点で脆弱なサーバー実装になっている。

http://blog.64p.org/entry/2013/07/17/151532

当のブログの他の記事を見ても、どこまで分かって書いてるのか、(ぼくには)よく分からないのですけれど、多分、この辺りのことを書いているのだと思います。
http://msdn.microsoft.com/ja-jp/magazine/ff646973.aspx
http://www.hpenterprisesecurity.com/vulncat/ja/vulncat/objc/denial_of_service_regex_evaluation.html

これを気にするなら、置換が無い preg_match() も脆弱性に該当します。
サニタイズはちょっと難しいですけど、バリデーションという意味なら、グルーピングの表現をはじいてあげる感じになると思います。

if (preg_match('/[^\\\\]\(/', $input)) {
    グルーピングの表現がある!
}
id:onigirin

どうもありがとうございます。
第2引数のことは了解済みです。

脆弱性の方も、参照URLで理解できました。
どの正規表現でも問題があるなら、とりあえずグループ表現をはじくと、こちらの対策はできそうということで、対策法がわかり安心しました。

いろいろなサイトやスクリプトのコードを見ていると、この対策がされていないような気もするのですが、ひとつDOS対策の知識が増えて助かりました。

2013/07/19 20:11:13
id:kaji0120 No.3

回答回数59ベストアンサー獲得回数13

ポイント33pt

preg系は第二引数にeを指定する事だけでなく、ダブルクォーテーションのルールなど結構注意すべき脆弱性が多いです。
何げなく使っている表現(特にダブルクォート)のことなど、知らなければ以下のブログに一度目を通しておいた方がいいと思います。

http://d.hatena.ne.jp/hnw/20100815
http://labs.s-cubism.com/blog/2010/03/18/176/

id:onigirin

どうもありがとうございます。
ダブルクォートは見逃しそうなので注意したいですね。
preg系の正規表現は、とりあえずeを使わずにグルーピングを避けて、バリデート利用してみようと思います。

2013/07/22 14:15:43

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません