入力バリデーションCモジュール、Validate PHPモジュールのスクリプト版を紹介します。既存のバリデーション用ライブラリとは一味違います。
Webアプリバリデーションの問題と対策
PHPのWebアプリに限った問題ではありませんが、「妥当な入力のみ受け入れる」はWebアプリでは当たり前にこれが行われていません。正しく処理できない入力データはどこまで行っても「正しく処理できない」ので出来る限り早く排除します。ソフトウェアエンジニアリングの基礎の基礎ですが、ほぼ全てのWebアプリができていません。
Webアプリの場合、エントリポイントが多い、汎用のHTTPプロトコルを利用している、といった仕様から「全ての入力をバリデーションする」は困難か不可能と思われていることがあります。
しかし、これは正しくありません。エントリポイントが多くて「取り扱うデータ種別」はそれほど多くありません。HTTPプロトコルが汎用でも「全てのデータをバリデーションできます」。
Validate for PHPはWebアプリによくある「入力データ妥当性検証の不足」をアドホックかつ容易に解消する為に利用できるライブラリです。
GitHubリポジトリ
https://github.com/yohgaki/validate-php-scr
デザイン
Validate PHPは入力バリデーション用のフレームワークとして設計されています。
Validate PHPはコードでバリデーションルールを定義するのではなく、PHP配列としてルール(Spec)を定義します。コードでルールを定義すると、余計なPHPコードを実行する必要があります。PHP配列で定義するとより効率良くバリデーションできます。
特定のエントリポイント(つまりMVCのコントローラー)のGET / POST / COOKIE / FILES / HTTP Headerをまとめて、一気に、効率良くバリデーションできます。
多くのバリデーションライブラリは全ての入力に対するホワイトリスト型バリデーションの実施が困難です。Validate PHPではこれを容易に行えます。
使用方法
個別に「入力値の形式」を定義さえすれば、「データ型を指定する感覚」で理想的な入力バリデーションを実装できます。
https://github.com/yohgaki/validate-php-scr/blob/master/src/examples/00-validate.php
使い方の基本は、入力データとなる変数をそれぞれ定義(以下は文字列の例)し
$string = [
VALIDATE_STRING,
VALIDATE_STRING_LOWER_ALPHA | VALIDATE_STRING_LF,
['min' => 4, 'max' => 128]
];
定義済みの入力データ仕様をエントリポイント(Webアプリの入り口となる箇所、MVCならC)で行うバリデーションの仕様の部品として利用します。
$specs = [
VALIDATE_ARRAY, // 1st should be Validator type
VALIDATE_FLAG_NONE, // 2nd should be validator flags
['min' => 3, 'max' => 3], // 3rd should be validator options.
[
'post' => [
VALIDATE_ARRAY,
VALIDATE_FLAG_NONE,
['min' => 4, 'max' => 5],
// min/max options are required for array to handle stupid attack efficiently.
// It's silly to perform costly validations for obvious attacks.
// NOTE: Any inputs could be optional by VALIDATE_FLAG_OPTIONAL.
[
'id' => $id,
'name' => $name,
'utf8' => $utf8,
'float' => $float,
'array' => [
VALIDATE_ARRAY,
VALIDATE_FLAG_NONE,
['min' => 2, 'max' => 2],
[
'id' => $id,
'string' => $string,
],
],
],
],
'get' => [
VALIDATE_ARRAY,
VALIDATE_FLAG_NONE,
['min' => 0, 'max' => 0],
[] // There should not be any query value.
],
'header' => [
VALIDATE_ARRAY,
VALIDATE_FLAG_NONE,
['min' => 2, 'max' => 50],
[
'USER_AGENT' => $user_agent,
'ACCEPT' => $accept,
'OTHER' => $accept,
],
],
],
];
$func_opts = VALIDATE_OPT_DISABLE_EXCEPTION; // Disable exception, to check errors, etc.
$results = validate($ctx, $inputs, $specs, $func_opts); // Now, let's validate and done.
RDBMSでいうならCHECK制約やデータ変更前のストアードプロシージャーによる制約を全ての入力値に対して強制できます。
簡単なバリデーションルールならコードを書く必要はありません。入力データ仕様を定義してしまえば、データ型を指定するのと同じ感覚でリクエストに対するバリデーション仕様を定義できます。
C言語モジュール版
スクリプト版のAPIが安定したら、Cモジュール版が同じように動作するように更新します。(その為に、C言語で実装しやすいような感じのPHPスクリプトを書いています)
https://github.com/yohgaki/validate-php
ドキュメント
ドキュメントはまだ無いので、サンプルスクリプトとテストコードを読んでください。
Web環境で動作するサンプルスクリプトは以下で見れます。
https://sample.ohgaki.net/validate-php/validate-php-scr/src/examples/00-validate-web.php
テスト用に書いているので読みづらいですが、サンプルスクリプトとしても利用可能です。
https://github.com/yohgaki/validate-php-scr/tree/master/src/tests
自動的にバリデーションルール(spec)を作成するツール
アプリケーションの入力を記録し、自動でバリデーションルールを生成することも可能です。
https://github.com/yohgaki/validate-php-scr/tree/master/src/tools
OWASP TOP 2017のA10では全ての入力をバリデーションし、不正な入力を検出し対応できないアプリケーションは脆弱なアプリケーションとしています。Webアプリセキュリティの基礎的要求事項ですが、多くのアプリケーションが実装していません。Validate PHPなら簡単に検出する所までは行えます。
アプリケーション入力から変数の特徴を完全かつ正確に把握することは不可能です。ヒント定義でより正確な定義を自動生成できるようにする予定です。
状態とバグ
Validate PHPはまだ開発中です。予告なくAPIの変更、データ形式(spec)の変更などが行われます。
まだバグがあると思うので見つけたら教えてください。こうしたら良い、こうして欲しい、といったご意見も歓迎です。