あっちに行って、そっちに行ってから、こっちに行くと不正なデータが登録出来る

アプリケーションの作りによっては、不正な画面遷移により入力チェックを回避して登録処理が行えてしまうことがあります。トランザクション処理のセキュリティとかに(多分)分類されるこの問題は、セッション変数を利用したアプリケーションにおいて発生することが多いと思います。(推測)

中でも問題発生の可能性が高いであろう(推測)、Strutsを使用したアプリケーションにターゲットを絞って何故このような問題が発生するのかを考えてみます。

セッション変数を利用したトランザクション処理の代表的な例としては、複数画面を使用したユーザ登録処理があげられるかと思います。画面1では基本情報入力、画面2では商品発送先情報入力、画面3ではアンケート入力などの入力項目がいっぱいある登録処理です。
このようなアプリケーションを実装するときに、セッション変数の使用が選択されるケースは多いでしょう。
セッション変数の使用と比べ、hidden値の使用には以下のような欠点があるからです。

  • hidden値を各画面(JSP)に記述するのがめんどくさい

戻るボタンの実装&扱うパラメータ値の変更を検討すると、めんどくさくて嫌になります。

  • データベース登録用のBLに渡すために、各画面全ての入力値がまとまったオブジェクトが作りにくい

一つにまとまってる方が嬉しいときがあります。(嬉しくないときもあります)

  • テスト項目が増えちゃう

やりとりされるパラメータの数が増えると、テスト項目が増えちゃうのでめんどくさいです。

そんなこんなで、セッション変数の使用が確定した場合の実装方法を考えると、入力値をオブジェクトに変換してくれるActionFormはスコープをセッションに指定して使用出来ることが判明します。
これは便利です。画面1、画面2、画面3、登録確認画面、登録処理といった一連の流れで、同じActionFormを使用したロジックを実装することが出来そうです。ActionFormには、画面1、画面2、画面3全ての入力項目用のフィールドを定義して、戻るボタン、次へボタン、確認ボタン、登録ボタンを実装したところ思い通りの動作をしてくれました。
次は入力値の検証機能を実装します。Validatorを使いましょう。セッション変数への保存なので、検証タイミングは画面1→画面2、画面2→画面3、画面3→登録確認画面でよさそうです。検証を通過しないと次の画面へは進めません。実装してみると思い通りの動作をしてくれました。あとは、2度押し防止と、CSRFとかいうめんどくさい問題に対応するために、登録確認画面→登録処理の遷移でTransactionTokenを使用した対策を入れておきましょう。
セキュリティ的にもばっちり対策してそうなアプリケーションの出来上がりです。

と、こんな感じで実装しちゃうと入力検証を回避されちゃう可能性があります。

あっちへ行ってこっちへ行ってから、そっちに行く

HTTPのアプリケーションで画面遷移の順番を強制させるには、なかなかメンドクサイ実装が必要です。
頑張って実装した結果、バグが発生してお客さんに怒られたりしたらやり切れないので、この辺の実装は省略されることが多いでしょう。
画面遷移の順番が制御されていないアプリケーションにおいて、
画面1、画面2、画面3、登録確認画面
が別々のウィンドウで開かれたケースを想定してみましょう。
それぞれの遷移時には入力値を検証しているので、最初に開かれた時には許可される値がそれぞれの画面にセットされている状態です。
この状態で、画面1の入力フォームに許可されていない値をセットし、画面2へボタンを押してみます。入力値が不正です。と画面1へ戻されてしまいました。
この状態で、登録確認画面上にある登録ボタンを押下してみます。登録が完了しました。と表示されたので、登録情報を見てみると・・・不正なデータが登録されている結果となりました。
これは問題です。何故このような問題が発生したのか原因を探っていきましょう。

ActionFormへパラメータがセットされる仕組み

Sessionスコープで使用するよう定義されたActionFormは同一セッション上である限り同じインスタンスが使いまわされます。
HogeForm form = session.getAttribute("HogeForm");
で取得したインスタンスから値を取得したり、セットしたりするイメージです。
値がセットされる条件は、

  1. リクエストパラメータの名前に対応したセッターが定義されている
  2. 定義されたパラメータが送信されてくる

ことの2点となります。

Validatorにより検証が実施される仕組み

次にValidatorによる検証の流れは以下となります。

  • ValidatorActionFormに値がセットされる。
  • ValidatorActionFormに値がセットされた値を検証する。

SessionスコープでのActionFormの使用時には注意が必要

上記の流れから、Sessionスコープに定義されたActionFormには不正な値が簡単にセットてしまうことが分かります。
予期せぬ画面遷移を考慮せず安易な実装をしていると
あっちへ行ってこっちへ行ってから、そっちに行く
ことにより、不正なデータが登録される結果を招くことになります。