Strutsには、複数のボタンが配置されたformにおいて、片方のボタンが押された場合は入力値チェックを行うが、もう片方のボタンが押された場合は入力値チェックを行わないといった制御を実装するために、Cancel機能というものが存在する。「戻る」ボタンを実装する場合などに使用されることがある機能であり、html:cancelタグと併用して動作する。
html:cancelタグを使用した場合、
<input type="submit" name="org.apache.struts.taglib.html.CANCEL" value="Cancel">
のようなsubmitボタンがHTMLとして作成される。Cancelボタンが押されたかどうかをAction#isCancelledメソッドを呼び出した戻り値によって判断し、後続の処理を分岐させることが可能な仕組みである。
protected void processPopulate(HttpServletRequest request,
HttpServletResponse response,
ActionForm form,
ActionMapping mapping)
throws ServletException {
中略
if ((request.getParameter(Constants.CANCEL_PROPERTY) != null) ||
(request.getParameter(Constants.CANCEL_PROPERTY_X) != null)) {
request.setAttribute(Globals.CANCEL_KEY, Boolean.TRUE);
}
}
(5)において、使用されるGlobals.CANCEL_KEYという属性は、Constants.CANCEL_PROPERTYまたはConstants.CANCEL_PROPERTY_Xがリクエストパラメータに含まれていた場合に、セットされるようRequestProcesser内で実装されている。
Constants.Constants.CANCEL_PROPERTYはorg.apache.struts.taglib.html.CANCELと、Constants.Constants.CANCEL_PROPERTY_Xはorg.apache.struts.taglib.html.CANCEL_Xと、それぞれ一致する。
従って、「Globals.CANCEL_KEYという属性が存在した場合、検証を行わずにtrueを返す」という挙動はCancel機能を実現させるために実装されていることが分かる。
Cancel機能により、html:cancelタグを使用して生成されたsubmitボタンが押された場合、入力値チェックはスキップされる。それでは、Cancel機能の使用を想定していないアプリケーションに対して、org.apache.struts.taglib.html.CANCELをパラメータに与え、リクエストを送信した際には、どのような挙動が示されるだろうか。
サンプルアプリケーション上で、先ほどと同様UserIDに「'」を入力し、org.apache.struts.taglib.html.CANCELをリクエストパラメータに付加して、OKボタンを押下した際の挙動が以下である。
入力値チェックがかからない状態で、Actionクラスへ処理が渡ってしまう結果となった。Action#isCancelledメソッドによるCancel状態のチェックを行っていないアプリケーションでは、入力チェックを通過していない値が後続の処理に渡されてしまう。サンプルアプリケーションでは、バインド変数などの安全な仕組み【注】を使用せずに、SQLを組み立てているため、入力値チェックを回避されてしまうと、SQLインジェクションの危険が発生することになる。
【注】
PreparedStatementを使用していれば、入力チェックを回避されても、SQLインジェクションの危険性を軽減できる。多層の防御態勢を取って、セキュリティ強度を高めるようにしてほしい。
実は、この現象はStruts 1.2.8以前のバージョンに存在する既知の脆弱性として報告されている問題である。
org.apache.struts.taglib.html.CANCELをリクエストパラメータに付加するだけ、という容易な手法で攻撃が成功するため、危険度は高い。対策が必須な問題であるといえるだろう。
Copyright © ITmedia, Inc. All Rights Reserved.