Webシステムを組む上で、データの入出力をする際には特有の注意をする必要があります。今回は、入力側について触れてみます。
入力値のバリデーション
外部からの入力の特徴として、何を送りつけられるかわからないということがあります1。整数だと思っていたら文字列が来たり、スカラーを想定している箇所に配列が与えられる、というような事態も考えられます。
ということで、そんな「何が来るかわからない値」を「プログラム内で有効な値」として使えるのか検証する必要が出てきます。これがバリデーションです。
一口に「バリデーション」といっても、いろいろな切り口があります。
- データ型のバリデーション…整数、文字列、日付などデータ型が想定のものと一致するか
- データ形式のバリデーション…郵便番号のように書式が決まった文字列や、値の範囲が決まった数値などで、その範囲に入っているかのバリデーション
- ロジックのバリデーション…商談日より契約日のほうがあとになる、というような、ビジネスロジックに基づいたバリデーション
そして、「バリデーションで弾くべき異常値」としても、2通りが考えられます。
- ミスで来うる入力値
- ミスでも起きないような入力値
この分類に関しては、入力の受け付け方をどのようにしているかに依存します。
HTMLフォームで入力させる場合、状況によっては種類も違う値が<input>
に入力可能なこともありうるので、数値 - 文字列の違いも入力ミスと判断せざるを得ないかもしれません。このような状況で「ミスでも起きないような入力値」は、スカラーであるべきところに配列やファイルが来た、あるいは文字エンコードがおかしい、<select>
や<input type="checked">
で用意してあるフォームなのに適切でない値が来た、などごく限られます。
一方で、APIとして入力を受け付ける場合は、明らかに型が異なるようなものは400 Bad Request
で終わらせてしまって構わないでしょう。一方で、「そこは予約がいっぱい」のようにAPIを呼ぶ側でチェックしきれない2制約条件については、いったん受け付けてきちんと状況を示すレスポンスを戻す必要があります。
あと、バリデーションの重要なポイントとして、「何重にかけても(バリデーターの実行速度の問題を除けば)全く問題ない」ということがあります。コントローラーでパラメーターの名前と型など、簡単なチェックをするバリデーターを入れて、ロジックや値の範囲の検証はモデルで行う、というような分業も可能です。
バリデーションでやってはいけないこと
バリデーションを組む上で、不適切なこともあります。
値を変更してしまうこと
バリデーションの役割はあくまで値の検証であって、値を変更するのはシステムロジックの都合となります。ロジック側で値を変更する場合は、変更後の値に対してもバリデーションを通す、あるいは通る値なのか確認する必要があります3。
ブラックリストによる検証
特定のキーワードを禁止した掲示板がどうなるのかを見れば火を見るより明らかですが、ブラックリストでバリデーションしても、よくて対症療法にしかなりません。HTMLなど、機能の多い言語を一般ユーザーからの4入力として受け付ける場合、受け付けるタグと属性をホワイトリストで洗い出して、残りは全部アウト、というような形にすることが必要でしょう。
-
ユーザーが入力する際にフォームを用意して、特定の形で入力させることはできますが、フォームを無視してリクエストを投げることも可能なので、「HTMLフォームやJavaScriptで行うバリデーション」は、悪意のある攻撃者に対してはまったく無力です。 ↩
-
事前にチェックしておいても、APIを送信するまでにいっぱいになっている危険性もあります。 ↩
-
エンコードレベルで壊れた文字列(通して有意になることもほぼないので、事前に弾いてしまうほうがいいでしょうが)やHTMLの断片などを無理やり変換してしまうと、状況によってはバリデーションで弾いたはずの文字列が生成してしまうことがありえます。 ↩
-
システム管理側のフォームであれば、「何を入力してもいい」が許される場面もあるかと思います。 ↩