Skip to content

PHP バグ・脆弱性の温床10連発

公開日:

札幌市中央区札幌市民交流プラザで開催された『PHPカンファレンス北海道2019』でアンカンファレンス(20分)として発表しました。

Download PDF

スライドテキスト

Page 1

PHP

バグ・脆弱性の温床10連発

Kill your PHP code by hitting 10 combos

[2019-09-21]PHPカンファレンス北海道2019

#phpcondo

Page 2

お前誰よ

  • うさみけんた (@tadsan) / Zonu.EXE
  • GitHub/Packagistでは id: zonuexe
  • ピクシブ株式会社 pixiv事業本部
  • Emacs Lisper, PHPer
  • Emacs PHP Modeのメンテナ引き継ぎました
  • 好きなリスプはEmacs Lispです
  • Qiitaに記事を書いたり変なコメントしてるよ

Page 3

Page 4

Page 5

Page 6

実家は近所です!!!

Page 7

Page 8

前回のぺちこん北海道2016がカンファレンスデビュー戦

Page 9

ついでにその前は札幌市中央区Ruby会議01

Page 10

さて

Page 11

PHPカンファレンスは楽しかったですか!

Page 12

ここで学んだことは今後の仕事に活かしていきましょう

Page 13

本題

Page 14

Page 15

Page 16

ということでクイックにいきましょう

Page 17

10連発

Page 18

ただしタイトルの「10連発」は任意の進数表記とする

Page 19

クイック

PHP

バグ・脆弱性の温床10連発

Kill your PHP code by hitting 10 combos

[2019-07-31]第140回 PHP勉強会@東京

#phpstudy

Page 20

例題1

<?

$id = $_REQUEST['id'];if (!is_numeric($id))printf("<p>{$id}は正しいIDではありません</p>");

?>,

Page 21

short open tagはphp.iniの設定依存なので、

例題1

基本は <?php または <?=

<?

$id = $_REQUEST['id'];if (!is_numeric($id))printf("<p>{$id}は正しいIDではありません</p>");

?>,

Page 22

short open tagはphp.iniの設定依存なので、php.ini依存かつ、

例題1

基本は <?php または <?=

$_GETと$_POSTが混ざると不適切な取り扱

<?

いされる傾向がある

$id = $_REQUEST['id'];

if (!is_numeric($id))

printf("<p>{$id}は正しいIDではありません</p>");

?>,

Page 23

short open tagはphp.iniの設定依存なので、php.ini依存かつ、

例題1

基本は <?php または <?=

$_GETと$_POSTが混ざると不適切な取り扱

<?

いされる傾向がある

$id = $_REQUEST['id'];

if (!is_numeric($id))

printf("<p>{$id}は正しいIDではありません</p>");

何を期待するのか

?>,

不明瞭だがMySQLのAUTO_INCREMENTなサロゲートキーなら不適切

Page 24

short open tagはphp.iniの設定依存なので、php.ini依存かつ、

例題1

基本は <?php または <?=

$_GETと$_POSTが混ざると不適切な取り扱

<?

いされる傾向がある

$id = $_REQUEST['id'];

if (!is_numeric($id))

printf("<p>{$id}は正しいIDではありません</p>");

何を期待するのか

?>,

不明瞭だがMySQLのAUTO_INCREMENTなサロゲートキーなら不適切

printfフォーマットに変数埋め込みをしない (入力値に%が含まれるとWarningが発生)

Page 25

short open tagはphp.iniの設定依存なので、php.ini依存かつ、

例題1

基本は <?php または <?=

$_GETと$_POSTが混ざると不適切な取り扱

<?

いされる傾向がある

$id = $_REQUEST['id'];

if (!is_numeric($id))

printf("<p>{$id}は正しいIDではありません</p>");

何を期待するのか

?>,

不明瞭だがMySQLのAUTO_INCREMENTなサロゲートキーなら不適切

printfフォーマットに脆弱性ではないが変な文字が混変数埋め込みをしない (入力値に%が含まれる

ざってるので ?> は消す

とWarningが発生)

Page 26

short open tagはphp.iniの設定依存なので、php.ini依存かつ、

例題1

基本は <?php または <?=

$_GETと$_POSTが混ざると不適切な取り扱

<?

いされる傾向がある

脆弱性じゃないけど { は一文でも几帳面に付ける方がオススメ

$id = $_REQUEST['id'];

if (!is_numeric($id))

printf("<p>{$id}は正しいIDではありません</p>");

何を期待するのか

?>,

不明瞭だがMySQLのAUTO_INCREMENTなサロゲートキーなら不適切

printfフォーマットに脆弱性ではないが変な文字が混変数埋め込みをしない (入力値に%が含まれる

ざってるので ?> は消す

とWarningが発生)

Page 27

改善案は各自への宿題とします

Page 28

例題2

const VALIDATE_PATTERN = "/^ # begin([a-zA-Z0-9])+([a-zA-Z0-9\._-])* # localpart@ # at mark([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+ # host$ # end/x";

$email = filter_input(INPUT_GET, 'email');if (!preg_match(VALIDATE_PATTERN, $email)) {echo "Bad mail address!!";}register_account(strtolower($email), $password);

Page 29

PCRE正規表現は /x 修飾子を付けると空白が無視されるので、これはGood

例題2

const VALIDATE_PATTERN = "/^ # begin([a-zA-Z0-9])+([a-zA-Z0-9\._-])* # localpart@ # at mark([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+ # host$ # end/x";

$email = filter_input(INPUT_GET, 'email');if (!preg_match(VALIDATE_PATTERN, $email)) {echo "Bad mail address!!";}register_account(strtolower($email), $password);

Page 30

PCRE正規表現は /x 修飾子を付けると空白が無視されるので、これはGood

例題2

だが、バリデーション(妥当性検証)のために正規表現で判定するのはだめ!!!

const VALIDATE_PATTERN = "/^ # begin([a-zA-Z0-9])+([a-zA-Z0-9\._-])* # localpart@ # at mark([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+ # host$ # end/x";

$email = filter_input(INPUT_GET, 'email');if (!preg_match(VALIDATE_PATTERN, $email)) {echo "Bad mail address!!";}register_account(strtolower($email), $password);

Page 31

PCRE正規表現は /x 修飾子を付けると空白が無視されるので、これはGood

例題2

だが、バリデーション(妥当性検証)のために正規表現で判定するのはだめ!!!

FILTER_VALIDATE_EMAILというフラグを使えば取得と同時に検証できる

const VALIDATE_PATTERN = "/^ # begin([a-zA-Z0-9])+([a-zA-Z0-9\._-])* # localpart@ # at mark([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+ # host$ # end/x";

$email = filter_input(INPUT_GET, 'email');if (!preg_match(VALIDATE_PATTERN, $email)) {echo "Bad mail address!!";}register_account(strtolower($email), $password);

Page 32

PCRE正規表現は /x 修飾子を付けると空白が無視されるので、これはGood

例題2

だが、バリデーション(妥当性検証)のために正規表現で判定するのはだめ!!!

FILTER_VALIDATE_EMAILというBad って表示してるだけで、処理はフラグを使えば取得と同時に検証できる

const VALIDATE_PATTERN = "/^ # begin([a-zA-Z0-9])+([a-zA-Z0-9\._-])* # localpart@ # at mark([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+ # host$ # end/x";

停止できてない!!!!

$email = filter_input(INPUT_GET, 'email');if (!preg_match(VALIDATE_PATTERN, $email)) {echo "Bad mail address!!";}register_account(strtolower($email), $password);

Page 33

PCRE正規表現は /x 修飾子を付けると空白が無視されるので、これはGood

例題2

だが、バリデーション(妥当性検証)のために正規表現で判定するのはだめ!!!

FILTER_VALIDATE_EMAILというBad って表示してるだけで、処理はフラグを使えば取得と同時に検証できる

const VALIDATE_PATTERN = "/

^ # begin

([a-zA-Z0-9])+([a-zA-Z0-9\._-])* # localpart

@ # at mark

([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+ # host

$ # end

/x";

停止できてない!!!!正規化は検討が必要(本来ローカルパートは大文

$email = filter_input(INPUT_GET, 'email');

if (!preg_match(VALIDATE_PATTERN, $email)) {

echo "Bad mail address!!";

}

register_account(strtolower($email), $password);

字小文字区別するが、実際はサービスの実装依存)

Page 34

例題2++

// これならどうだ!

$email = filter_input(INPUT_GET, 'email',FILTER_VALIDATE_EMAIL);if ($email !== false) {echo "Bad mail address!!";exit;}

[$local, $host] = explode('@', $email);$normalized = $local . '@' . strtolower($host);

register_account($email, $password);

Page 35

例題2++

// これならどうだ!

これでも

良くないことがあるので続きは懇親

$email = filter_input(INPUT_GET, 'email',FILTER_VALIDATE_EMAIL);if ($email !== false) {echo "Bad mail address!!";exit;}

会で!!!!!!!!

[$local, $host] = explode('@', $email);$normalized = $local . '@' . strtolower($host);

register_account($email, $password);