フォームヘルパーでブラックホール行きまくる場合に気をつけるべき点
セキュリティコンポーネントを利用しつつフォームヘルパーでフォームを生成すると、セキュリティ評価用のトークンが hidden 要素で同時に生成される。
セキュリティ評価用と言ってもセッションに保存されるデータと、フォームの hidden 要素に渡されるデータは全く同じものなので、セッションハイジャック的な攻撃に対しては無防備だと思ったので考えてみた。
セキュリティコンポーネント+フォームヘルパータッグでの働き
- セキュリティコンポーネントはリクエストの度にセキュリティ評価用のデータ(トークン)を生成する。
- 生成したトークンはセッションに保存。(作成日時など、有効期限の評価に関連するデータも合わせて保存してある)
- コントローラーのパラメーターにセキュリティトークンを渡す。
ここまではセキュリティトークンの働き。
- フォームヘルパーでは、FormHelper::create() では、コントローラから受け取っているパラメーターにセキュリティトークンが含まれていた場合、その情報を元に hidden 要素としてトークンをフォームに追加。
- FormHelper::end() が呼ばれると「今までに生成した入力要素」とセキュリティトークンを元にフィールド用トークンを生成。
- hidden 要素などの「リクエストに含まれていても値が固定である」と言う部分を静的、逆を動的とした場合に静的なパラメータはパラメータ名をキーにした連想配列で、動的なパラメータの場合はパラメータをデータとする配列(数値キー)として、それらパラメータで配列を作り、シリアライズして少々の難読化を施してフォームに追加。
- 追加が完了したらフォームヘルパーで生成した入力要素の情報を削除。
ここまでがヘルパーの働き。
二つを連携させるのに難しい設定は必要ないけれど、フォームヘルパーで入力要素だけを作ったりしているとどうやってもセキュリティコンポーネントの評価が通らなくなる場合がある。
フォームヘルパーは「今回のフォームから送信されてくるパラメータはこれとこれとこれ」と言う具合に予め制限し、その制限の内容をフィールド用トークンとしてフォームに埋め込んでいる。従って、複数のフォームを設置する場合にはFormHelper::end() で生成したパラメータの情報をクリアしてから新たなフォームを生成する必要がある。
FormHelper::end() ではなく、FormHelper::create() でパラメータ情報をクリアしていればこのような問題には当たらないと思うけれど、逆のパターンだとしても「ロジックの雑さを許容する」分潜在的な危険性を持ったままだと考える事も出来る。
しかし、このやり方ではセッションの所有者である事を保証できない。セッションに保存するのは発行したセキュリティトークンとクライアントの IP アドレスや UA などで生成したハッシュ値をフォームヘルパーに渡すような、客観的な評価基準を設けないと難しいのでは。