Page 1
入力+検査=型安全
Make PHP type safe by validating input
pixiv Inc.
USAMI Kenta
2023-09-16 PHPカンファレンス沖縄2023
公開日:
by USAMI Kenta@tadsan
に沖縄県中頭郡西原町の琉球大学 理系複合棟で開催された『PHPカンファレンス沖縄2023』でレギュラーセッション(30分)として発表しました。
2023-09-16 PHPカンファレンス沖縄2023
お前誰よ
PHPの進化は型宣言の進化
function add($a, $b) {return $a + $b;}
int + intって本当にintなの?
function add(int $a, int $b): int {return $a + $b;}
ひとつの解決策ではあるが… 不必要にfloatを強制するのか
function add(float $a, float $b): float {return $a + $b;}
あえて型宣言を省略する
/*** @param int|float $a* @param int|float $b* @return int|float*/function add($a, $b) {return $a + $b;}
function add(int|float $a, int|float $b): int|float {return $a + $b;}
いたるところに型が書けるようになった
PHPStanとは
高速な解析を実現していた
201X年、PHPは型の炎に包まれた!!
いまやPHPは静的型付きと言っても過言ではない(本当か…?)
だが型なしは滅びていなかった
型なしはどこからくるの?
みなさんに覚えておいてほしいこと
Validation
Sanitize
Validation
Sanitize
Escape
これは気にしなくていい
自信をもって説明できますか?
クエリパラメータからID値をとりたい
/** IDから記事を取得 */function getById(int $id): Article{// 中でデータベースに問い合わせ}
実際あぶない
そもそも何者
型なしとはどういう状態か
(関数呼び出しをしたときにTypeErrorが出ないか安全だと言いきれない)
PDOStatement::fetch()
// ?id=1$_GET['id'] === '1';
// ?id=a$_GET['id'] === 'a';
// ?id[]=a$_GET['id'] === ['a'];
// ?id[foo]=bar$_GET['id'] ===['foo' => 'bar'];
キャストすればいいのか
危険ではないがよくはない
// ?id=32x$id = (int)$_GET['id'];$id === 32;
if (is_numeric($_GET['id'])) {
throw new BadRequestException();
}$id = (int)$_GET['id'];
整数 123小数 1.23
指数表記1.844674407371E+1
前後にスペース
だいたいのIDは正の整数だけ
// ?id=1.23 if (is_numeric($_GET['id'])) {
throw new BadRequestException();
}$id = (int)$_GET['id'];
安全に
int|false
$id = filter_var($_GET['id'] ?? '',FILTER_VALIDATE_INT);
安全に
int|false
$id = filter_var($_GET['id'] ?? '',FILTER_VALIDATE_INT,['options' => ['min_range' => 1,]]);
https://phpstan.org/try
https://php-play.dev/
うまいこと値のバリデーションできる標準関数
……話は遡り2007年
ホルモンのPHP (前半)
いる様子
ホルモンのPHP (後半)
ホルモンのPHP (後半)
フィルタにはサニタイズ機能もある
フィルタにはサニタイズ機能もある使わないで!!
フィルタ関数を使えば解決するのか
なんだよ外部公開してないライブラリの自慢かよ
キタカミの里から帰ってきたら公開したい!!
対応予定
スーパーグローバル($_XXX)
PSR-7 ServerRequest
