連載
» 2006年04月27日 00時00分 公開

サーブレットコンテナが抱える問題を認識するStrutsで作るセキュアWebアプリケーション(2)(2/3 ページ)

[安西真人,三井物産セキュアディレクション株式会社]

サーブレットコンテナに依存しない解決手法

 実運用において、サーブレットコンテナに依存する問題は解決がなかなか難しい。脆弱性が解決されたバージョンがリリースされているとしても、同一サーバ上で複数のアプリケーションが稼働しているケースでは、バージョンアップのタイミングを調整することが非常に困難だ。

 また、開発の初期段階ではTomcatのようなフリーの製品を使用して、後期段階になって初めて本番運用で使用するサーブレットコンテナでの動作確認を行うというケースもあるだろう。この場合、リリース直前にならないと問題が発覚しない事態が起こり得る。

 こうした問題を考慮すると、アプリケーションサーバに依存しない解決手法を検討しておくことが望ましい。個々のアプリケーションで対応可能な解決手法としては、以下が考えられる。

  • エラーメッセージに入力値が含まれる場合、あらかじめHTMLエンコードしておく
  • エラーメッセージから入力値を取り除く
  • 例外が発生しないようなコーディングをする
  • カスタムエラーページを必ず定義する

 では、それぞれの解決手法について考察していく。

エラーメッセージに入力値が含まれる場合、あらかじめHTMLエンコードしておく

推奨度:×

String input = testForm.getInputMsg();
throw new Exception(":渡されたパラメータ" + org.apache.struts.util.ResponseUtils.filter(input));

 この手法は明らかな間違いである。例外をスローした時点では、このメッセージがHTML上に出力されるとは確定していない。エラーメッセージの詳細はロギングするが、HTML上には出力しないケースも多々あるだろう。

 また、脆弱性のあるサーブレットコンテナ上では一見正しく対応できるように感じられるが、脆弱性のないサーブレットコンテナで動作させると、以下のように多重エンコードがかかるという恥ずかしい結果ともなる。

画面3 多重エンコードがかかる(画像をクリックすると拡大します) 画面3 多重エンコードがかかる(画像をクリックすると拡大します)

エラーメッセージから入力値を取り除く

推奨度:×

 この手法も間違いだ。例外オブジェクトを構築する際に入力値を渡すことの意味は、例外の原因を分かりやすくすることにある。アプリケーションの保守性を低下させるような対策は行うべきではない。

例外が発生しないようなコーディングをする

推奨度:△

 個々のアプリケーションでできるだけ例外が発生しないようなコーディングをすることは可能だろう。入力値が例外の要因となり得るならば、あらかじめ入力値チェックを行うよう正しく実装することで、問題を回避することができる。

 ただし、入力値チェックに漏れがあった場合、即セキュリティ上の問題へと結び付く可能性があるため、入力値チェックだけに頼った対策は危険であることを認識してもらいたい。この場合、ActionFormに定義したプロパティだけでなく、Strutsが使用するパラメータについても必ずチェックする必要がある。

 Strutsが使用するパラメータが原因となって問題が発生する例として、脆弱性として報告・修正された経緯があるDispatchActionが出力するエラーメッセージについて解説しよう。

 まず、Struts 1.2.8を使用してDispatchActionを継承したクラスを作成する。

public class DispatchTestAction extends DispatchAction {
  public ActionForward foo (
      ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response)
    throws Exception {
    return mapping.findForward("success");
  }
}
DispatchTestAction.java

<action
path="/DispatchTest"
  name="TestForm"
  scope="request"
  validate="false"
  parameter="methodKey"
  type="jp.mbsd.was.struts.DispatchTestAction">

</action>
struts-config.xml

 作成したアプリケーションのクエリストリングに以下を指定して、リクエストを発行してみる。

methodKey =<script>alert('XSS');</script>


画面4 /DispatchTest.doのクエリストリングにmethodKey =&lt;script&gt;alert('XSS');&lt;/script&gt;を指定 画面4 /DispatchTest.doのクエリストリングにmethodKey =<script>alert('XSS');</script>を指定

 Tomcat 5.5.15 を使用した場合、スクリプトは動作しなかった。DispatchActionの実装にはリフレクションが使用されているため、メソッドが見つからない場合のroot causeとして、java.lang.NoSuchMethodExceptionがスローされる。この際、見つからなかったメソッドはエラーメッセージとして格納されており、スタックトレースとして出力される。Tomcat 5.5.15のようなメッセージをHTMLエンコードしているサーブレットコンテナでは問題は起きないが、Tomcat 4.1.27のようなHTMLエンコード漏れがあるサーブレットコンテナでは、問題が発生することになる。

 このような問題をStrutsの脆弱性と位置付けるならば、まだ報告されていない潜在的な問題が存在している可能性があるだろう。ちなみに筆者は、これらがStrutsの脆弱性であるとは思わない。製品のデフォルトエラーページにおける、HTMLエンコード処理はサーブレットコンテナが責務を負うべきであると考えるからだ。

 「Strutsが使用するパラメータが起因となるとはいっても、methodKeyというパラメータが送信されるのだから、パラメータの入力値チェックを行えばよいのでは」という意見もあるかもしれない。ただし、そのような手法を取る場合は、Strutsの実装を正しく理解し、本当に問題が出ないのかどうかを確認する必要がある。安全性の保証が難しい問題であるため、以下に述べるカスタムエラーページの定義を併用して対応することを推奨したい。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。