Spring MVCの潜在的な問題を指摘するあるセキュリティ勧告が出された(2008年7月16日)(リンク)。これはSpring MVCを使って実装されてきたアプリケーションに影響を与える可能性がある。この問題はサーバサイドでの処理とクライアントサイドのパラメータに関わる。InfoQはこの問題を詳しく分析し、またこの問題を指摘したOunce Labs(リンク)に話を聞いた。
公式のプレスリリース(リンク)ではこの問題を次のように述べている。
ウェブアプリケーションをクロスサイトスクリプティング(XSS)やSQLインジェクション攻撃にさらす通常のアプリケーション脆弱性と違い、これらの新しいタイプの脆弱性はSpring Framework内のセキュリティフローについてではなく、もし実装が適切におこなわれなかった場合にビジネス上重要なアプリケーションを攻撃にさらすことになる設計上の問題です。Spring Frameworkを使ったアプリケーションの設計フェーズとテストフェーズにおいて正しいセキュリティ意識を持つことは、デプロイ後の攻撃から企業を守ることになります。
そしてOunceはこの問題をより詳しく説明する。
まずは問題なのはデータバインディングと呼ばれる処理です。Spring MVCは、フォームのフィールドに入力されたデータを、それに対応したオブジェクトモデルを実装するjavaビーンズに自動的にセットする機能を備えています。これで問題になるのは、同一のビーンを複数のフォームについて使っていた時、各フォームから送信されてくるデータが異なるということです。たとえば、あるウェブアプリケーションのあるビーンがユーザアカウントを表していたとして、このビーンを更新する2つのフォーム、一方は新しいアカウントの作成のためで、もう一方は既存のアカウントを更新するためのフォームがあったとします。するとアカウント更新のフォームで別のユーザのアカウントを変更することができてしまう可能性があります。2つ目の脆弱性はビジネスプロセスをコントロールするのにユーザでコントロール可能なデータを使うことから起きます。セキュリティの世界では悪意のあるスクリプトを含んだりSQLインジェクションのような攻撃を起こす可能性があるユーザデータのチェックについては高い意識がありますが、それだけでなくビジネスプロセスをコントロールするのに使われるデータでユーザコントロール可能なものも全てチェックをしないといけないのです。たとえば、Spring MVCを使ってつくられた取引システムがあって、そこに3つのコントローラがあったとします。メインのコントローラは新しい取引リクエスト、別のコントローラは取引リクエストのチェック、あとのコントローラは取引の実行を処理するとします。もしこの一連の処理のいずれかのポイントで、次の処理を行うコントローラを指定する画面があって、それをユーザが使ったとしたら、ビジネスプロセスを破綻させてチェックのすんでいない取引を行うことができてしまいますね。
SpringSource(Springの開発元企業)のセキュリティ勧告(リンク)でもこの2つの問題に詳しく触れて、どのようにこの両方を解決するかを説明している。
編集不可のフィールドに対するデータ入力を未然に防ぐには、バインディングを行うフィールドをDataBinderで明示的に設定しないといけません。このために、アプリケーションで使う各DataBinderインスタンスのallowedFieldsプロパティをセットします。これを主要なコントローラ実装でどのようにおこなえばいいかを以下の例で示します。
- SimpleFormController ー initBinder(HttpServletRequest, ServletRequestDataBinder)をオーバーライドし、引数に与えられたServletRequestDataBinderインスタンスのsetAllowedFields(String[])を呼び出す
- MultiActitonController - メソッドの中でインスタンス化する全てのServletRequestDataBinderのインスタンスのsetAllowedFieldsを呼び出す
- @Controller - Contollerを明示的に設定するメソッドの中にWebDataBinderを挿入する@InitBainderアノテーションを使う。その ContorollerクラスのsetAllowedFields(String[])を呼び出してそのControllerクラスでバインディング可能なフィールドを指定する。もしallowedFieldsの対象をメソッドごとに変える必要があるのなら、@InitBinderを付けたメソッドで HttpServletRequestを受け取るようにし、現在のリクエストのマッピングを変更する。
- AbstractWizardFormController ー initBinder(HttpServletRequest, ServletRequestDataBinder)をオーバーライドし、引数に与えられたServletRequestDataBinderインスタンスのsetAllowedFields(String[])を呼び出す。ページごとのallowFieldsを設定するには getCurrentPage(HttpServletRequest)を呼び出す。
ModelViewインジェクションの問題を未然に防ぐには、クライアントにビューの名前を選ばせないようにするだけです。ビューの名前はサーバサイドの責任です。
Ounceは同じような問題を抱えているフレームワークが他にもあるに違いないとも述べた。
このような脆弱性は全ての自動バインディングをおこなっているフレームワーク、またはアプリケーションのビジネスプロセスをユーザがコントロールできるポイント全てに存在します。私はいくつかの独自フレームワークで同じような脆弱性を見てきましたし、Ruby on Railsアプリケーションも最近調べてみましたがやはり同じような脆弱性がありました。問題なのはこれらのフレームワークの多くが、ディベロッパがコードをあまり書かないでもアプリケーションを作れることを意図して作られていることです。(デフォルトで)簡単かつセキュアにアプリケーションを作れるようにフレームワークが作られるかぎり、簡単に書けてしまうセキュアでないアプリケーションを多く抱えてしまうのです。
原文はこちらです:http://www.infoq.com/news/2008/07/spring-mvc-advisory