Gunosyで配信されてきて唖然としたので久しぶりにエントリー。
前もって断っておきますが、私はこのエントリーしか読んでいません。徳丸氏という方も大垣氏という方も存じ上げません。なので、全く見当違いの内容になっているかも知れないのでその点はご容赦を。
さて。
私がこの徳丸氏のエントリーで唖然としたのは後半の以下の箇所。
これが本当に「世界の常識」なのでしょうか?私は見たことがありません。よろしければ、ソースを示していただければと思います。
彼が「見たことがない」というのは、大垣氏の主張をまとめた次のようなコードだそうです。
- 入力値のチェックはアプリケーションの仕様を元に行う
- このチェックには2種類あり、ユーザの「入力ミス」と「入力バリデーションエラー」である
- 入力バリデーションエラーとは、利用者の通常の操作では入力し得ない値を検出するものである
- 例として、JavaScriptによるチェック済みなのにサーバーに仕様外の値が来たら入力バリデーションエラーとして厳しく対処する
- (恐らく)入力ミスについては優しくナビゲートする
ちなみに、私は見たことがあります。というか、まさしく私はこのように作ってます。むしろ「見たことがない」というのが驚き。
見当違いなら申し訳ないけど、徳丸氏は自分が何を言ってしまったのが解っているのでしょうか?「見たことがない」ということは、徳丸氏が書いてきたコードにはセキュリティホールがあるってことになるのですが…。
私は大垣氏の見解に大いに賛同します。まさしく、バリデーションはセキュリティ対策であり世界の常識です。
はっきり言って、invalidな入力をするセッションは即切断したいし、リモートIPアドレスをブラックリストに入れて二度と接続できないようにしたいくらいです。(ちょっと大げさだが…)
なぜか。
HTTPではサーバーサイドのプログラムにどんなデータでも送りつけることができます。悪意を持ったユーザーは何をするか解らないし、その結果がどうなるかを100%想定することは不可能です。
だからvalidな値だけを想定し、それ以外はすべて蹴るようにします。また相手は悪意を持っているのですから、連続して同じ行為ができないように対策を施さなければなりません。
しかし、invalidな値を入力するのは悪意のユーザーだけとは限らない。善意のユーザーの「ミス」でもinvalidなデータは送られてきます。
そこでユーザーの悪意と善意を切り分ける必要が生じるわけです。
まず、サーバーサイドだけで構築するシステムを考えてみましょう。
サーバーサイドだけでは、ユーザーの善意と悪意を切り分けるのは難しいです。仕方がないのでユーザビリティを確保するためにフレンドリーにメッセージで間違いを指摘したり、再入力を促したりすることになります。
はっきり言いますが、これはユーザービリティのためにセキュリティを妥協しているにすぎません。
バリデーションにおけるユーザビリティとセキュリティを両立させるには、大垣氏が例示しているようにJavaScriptのようなクライアントサイドの仕組みが必要です。
まず、ユーザー入力をクライアントサイドでチェックします。invalidな入力であればフレンドリーに間違いを指摘し、再入力を促します。このようにすれば善意のユーザーによるinvalidな入力を排除し、ユーザビリティも確保することができます。
しかし悪意のユーザーにとってはクライアントサイドでのチェックは無意味。チェック機能を回避することなど容易なことだし、ブラウザのAdd-onなどの開発ツールを使えばHTMLを書き換えてどんな値でも送りつけることができます。そもそもHTMLフォームすら必要ありません。
そこでもう一度サーバーサイドでもチェックを行うわけです。
善意の入力はすでにクライアントサイドでチェック済みですから(仕様にもよるけど)サーバーサイドのチェックに引っかかることはありません。
つまり、サーバーサイドのチェックでinvalidになるものはほぼ確実に悪意の入力と断定できるわけです。したがってサーバーサイドでinvalidと判断されたならば、セッションの強制切断など強硬な対応をすることが可能になります。
…と、大垣氏は言いたかったのではないかと推測しているのですがどうでしょう?