谷本 心 in せろ部屋

はてなダイアリーから引っ越してきました

ValidationとVerification

こないだのドン引き最終回でもチラっと出た、これ。


ValidationとVerification。
言葉的には「妥当性の確認」と「検証」なんだけど、
ここでは「画面入力のチェック」と「サービスの引数チェック」って事にしておく。


図にするとこんな感じ。


Webアプリケーションのセキュリティでウダウダ言ってる問題って
実は、この2種類に分ければ、随分と上手く整理できそうなんですよね。


ときに、
フレームワーク使って開発してると、バリデーションの責務が増えがち。
だって、バリデータとロジックの双方でチェックなんてしたくないから。
だから複数フィールドバリデータとか、無理してキモい事やったり
バリデータからDBにアクセスしたり、おいおい、それ何てLogic? みたいな状況になる。


逆に、バリデータはソコソコに、ロジックできっちりチェックすると
決めてるプロジェクトも多いと思うんだけど、
そんな場合も、もし、hidden書き換え対策だー、とか言って
sessionにDtoを持たせてたりすると、
ロジックに到達した時点でDtoには値が反映されてるわけだから、これヤバい。
詳しくは書かないけど、ヤバい。チェックの意味があんまりない。


セッションは極力使わず、入力はhiddenを使って保持して、
値はロジックでもチェックする、多分これが一番安全。


さて、
ここで最初に書いた「Validation」と「Verification」に話を戻しましょう。


「入力値のチェック」っていうのを、何のために行なうかを考えると、
やはり「ユーザビリティ」のためでしょう。
最後のコミットする段階になって「ふつうにだめー」とかってDBに怒られると、
もう腹が立って仕方ないから入力段階でバリデーションを行なう。


ここで勘違いしちゃいけないのは、
このバリデーションはセキュリティのためじゃないってこと。


いくらバリデーションタグを使っても、hiddenタグは書きかえられちゃうし、
sessionの値も、結局、安全とは言えない。


セキュリティのために行なうのは、Verification。
つまり、サービスを呼び出し時の引数のチェック。


Dtoがリクエストスコープだったら、そのままサービスに渡して良いけど
Dtoをセッションスコープで保持した場合は、ディープコピーを作ってから渡す。
それをService層でチェックする。


ほら、みんなWebサービスだったら同じことするでしょ?
それをWebアプリケーションでもやるだけ。


この原則を守ってさえいれば、
別に複数ウィンドウ対策とか、画面フローの制御とか行なわなくて良い。
そんな「変な」操作をして困るのは、操作した人だから。
システムには影響を与えないから。


ここで、サービスの引数となるDtoにはアノテーションを入れておいて、
Interceptorでチェックしてあげるのが、一番楽なのかな。


というのを形にすると、最初に見せた図の通りになる。

Validationは、HTMLに記述したValidatorで行なって
Verificationは、Formに記述したアノテーションに反応して行なう。
もちろんVerificationは複数フィールドの相関チェックにも対応するし、
Daoアクセスなんかも可能、という位置づけで。


ただ、これでも、二重サブミットと、CSRFは防げないから、
ワンタイムトークンの発行だけは必須。
確認画面の表示時にでもワンタイムトークンを渡してあげて、
それでコミットを行なえば良い。


これでどう?