ユーザの入力は絶対信頼してはいけないお話
目次
ユーザは基本的に何を入力してくるかわからない
ユーザという存在は悪意の有無にかかわらずどんなデータを送信してくるか分かりません。
例えばvarchar型のカラムに保存される入力のバリデーションがあったとします。
「オーバーフローしないように255文字以内かどうかのチェックだけしておいたら大丈夫かな?」
いいえ違います。もし同じname属性で配列データを送信されたらどうなるでしょう?
当然ですが文字数以前に文字列であるかどうかのバリデーションも必要になります。
その逆もしかりで配列形式でデータを送信してもらい、json型として保存したいのに同じname属性で平文のテキストを送られる可能性もあります。
例えばLaravelでのバリデーションの正誤例だと次のようになります。
誤ったバリデーション設定
'name' => [
'nullable',
'max:255',
],
'choices.*.index' => [
'required',
'numeric',
],
'choices.*.value' => [
'required',
'string',
'max:255',
],
正しいバリデーション設定
'name' => [
'nullable',
'string', #文字列であることをバリデート
'max:255',
],
'choices' => [
'array', #配列であることをバリデート
],
'choices.*.index' => [
'required',
'numeric',
],
'choices.*.value' => [
'required',
'string',
'max:255',
],
これは1例にすぎず、その他にもSQLインジェクションや、意図しないスクリプト実行の防止など、考慮すべき点はたくさんあります。
フロントエンドでバリデーションしたから大丈夫?
最近ではJavaScriptやReactなどのフロントエンドフレームワークを利用して画面遷移せずにその場でバリデーションを行いそもそも入力内容に誤りがあるとフォーム送信できない仕組みもあります。
そこできっちりとバリデーションを行っていた場合バックエンド側のバリデーションは不要でしょうか?
ただバリデーションエラーがなくなった状態で開発者ツールなどでフォームの値を改ざんして送信される可能性は否定できません。
また、エラーが出て送信ボタンが押せない状態だったとしても無理矢理submitボタンを追加して送信される可能性もあります。
もちろん、フロントエンドでのバリデーションチェック時にあらかじめ入力値をバックエンドに送信してセッションに入力値を持たせてもいいかもしれません。
でもそのバックエンドに送信するajax通信も偽装されていたら?
結局バックエンドでもきっちりバリデーションする必要があります。
ではガチガチにバリデーションでチェックして拒否すべき?
もちろん想定される全てのパターンに対応するべきです。全てというと大変ですが、元々想定している値以外をはじく形で設定すれば良いのです。
1mmでも想定とずれていればバリデーションエラーとして入力画面に返すべきです。
厳しく疑いでも時にはユーザフレンドリーに
ただ悪意のない、少し勘違いしただけの入力は許容してあげるとさらによいシステムになります。
例えば次のような場合です。
- メールアドレスや数値を全角で入力してしまった
- フリガナをひらがなで入力してしまった
- 電話番号や郵便番号のハイフンを全角や長音で入力してしまった
- 電話番号や郵便番号のハイフンが不要なのに入力してしまった
これらの場合はバリデーション前に入力値をフィルターにかけてmb_comvert_kanaなどを使用して適切な想定されるように半角への変換、ひらがな>カタカナの変換、ハイフンの文字置換および除去などを行った上でバリデーションを実行するとよりユーザに優しいシステムになります。
さいごに
普段からこのようにバリデーションやフィルターを意識してシステムを構築していると個人的にお問い合わせフォームなどを利用した時に
「このフォームの作り雑すぎんか?!」
という職業病が発生する弊害?はありますが、そういった経験も反面教師として、同じようなシステムを作らないように気をつけて行きましょう!



















