前回までで、共有ブックマークの基本的な機能は一通りそろいました。これで、問題なくサービス開始、としたいところですが、その前に行うべき処理があります。
これまではユーザが入力した文字列のチェックを行わずに、そのままHTML文への出力 やSQL文の作成に使用していました。これまでの例で使用した文字列にはたまたま<や>、シングルクオート“'”が含まれていませんでしたが、もしユーザーがこれらの文字列を含む内容を登録したいと考えた場合、ページのデザインが崩れたり、SQL文の実行でエラーが出たりしてしまいます。また、ユーザーが悪意を持っていた場合に は、データの改ざんや破壊などを目的とした文字列がパラメータとして渡されることも考えられます。これらは、重大なセキュリティーホールであるため、特にパラメー タとして渡される値の扱いには注意が必要です。
そこで、入力された文字列を適切に処理する仕組みが必要になります。基本的には、HTML文やSQL文ではそのまま扱えない文字列を適切な文字列に置換することで対応します。
前回パスワードチェック用のメソッドを作成したMyUtilクラスに、文字列の置換を行うためのメソッド substitute を新しく追加し、それを用いて文字列の置き換えを行うことにします。
文字列の置換を行うメソッドでは、処理の対象となる文字列と、置換前の文字列、置換後の文字列を引数に取り、置換処理を施した文字列を返すものとします。このsubstituteメソッドの中身は次のようになります。
/** * 文字列の置換を行う * * @param input 処理の対象の文字列 * @param pattern 置換前の文字列 * @oaram replacement 置換後の文字列 * @return 置換処理後の文字列 */ static public String substitute(String input, String pattern, String replacement) { // 置換対象文字列が存在する場所を取得 int index = input.indexOf(pattern); // 置換対象文字列が存在しなければ終了 if(index == -1) { return input; } // 処理を行うための StringBuffer StringBuffer buffer = new StringBuffer(); buffer.append(input.substring(0, index) + replacement); if(index + pattern.length() < input.length()) { // 残りの文字列を再帰的に置換 String rest = input.substring(index + pattern.length(), input.length()); buffer.append(substitute(rest, pattern, replacement)); } return buffer.toString(); }
HTML文で&、<、>、"の記号を表示するためには、それぞれ&、<、>、"と記述する必要があります。共有ブックマークでは、タイトル、URL、コメントの入力をそのままHTMLで出力しているので、それぞれに対して、上記の記号を適切な文字列に変換する必要があります。しかしながら、上記で作成した置換用のメソッドsubstituteをそのまま使用すると、文字列の数×4回分の置換処理をプログラムの中に記述することになり大変です。ここでは、これらをまとめたHTMLEscapeというメソッドを新たに作成し、JSPプログラムからはこちらを使うようにします。
このメソッドHTMLEscapeは次のようになります。
/** * HTML 出力用に次の置換を行う * & -> & * < -> < * > -> > * " -> " * * @param input 置換対象の文字列 * @return 置換処理後の文字列 */ static public String HTMLEscape(String input) { input = substitute(input, "&", "&"); input = substitute(input, "<", "<"); input = substitute(input, ">", ">"); input = substitute(input, "\"", """); return input; }
SQL文では、テキストの値をシングルクオートで囲って表現するため、テキストの文字列中にシングルクオートが存在すると、正しく処理されません。また\記号も\\へ変換する必要があります。先ほど、HTML文をエスケープするためのメソッドを作成したのと同じように、SQL文用のエスケープ処理を行うSQLEscapeメソッドを次のように作成します。
/** * SQL文出力用に次の置換を行う * ' -> '' * \ -> \\ * * @param input 置換対象の文字列 * @return 置換処理後の文字列 */ static public String SQLEscape(String input) { input = substitute(input, "'", "''"); input = substitute(input, "\\", "\\\\"); return input; }
Javaのコーディングでは、ダブルクォート内の\記号はエスケープ記号として認識されてしまうため、文字列中で\を表現するには\\と記述する必要があります。従って、\を\\に置換するための記述は次のようになっていることに注意しましょう。
input = substitute(input, "\\", "\\\\");
それでは、実際に上記のメソッドを使用して、文字列の置換が適切に行われるかどうかをテストしてみます。テスト用に、次のような簡単なJSPプログラムを作成しました。
<%@ page import="atmarkit.MyUtil" contentType="text/html; charset=euc-jp" %> <% out.println(MyUtil.substitute("This is an input.", "an input", "the result")); out.println(MyUtil.HTMLEscape("<tag & ampersand escape>")); out.println(MyUtil.SQLEscape("MyUtil's SQL escape")); %>
上記のプログラムを実行した結果として出力された内容は、次のとおりです。適切に置換されれていることが確認できます。
This is the result. <tag & ampersand escape> MyUtil''s SQL escape
それではさっそく、HTML文のエスケープ処理をそれぞれのプログラムに組み込んでみます。分りやすいようにlist.jspへの組み込み例だけを紹介します。データベースから取得した内容に対してHTMLエスケープを行う処理は、次のように記述することになります。これと同様の処理を、それぞれのJSPプログラムのHTML出力を行う個所に組み込みます。
String title = MyUtil.HTMLEscape(rs.getString("title")); // タイトル名を取得 String url = MyUtil.HTMLEscape(rs.getString("url")); // URLを取得 String comment = MyUtil.HTMLEscape(rs.getString("comment")); // コメントを取得
続いて、SQL文への対応も行います。これは、実際にSQL文を作成する個所でSQLEscapeメソッドを使用することになります。例えば、いままでに作成したupdate.jspでは次のようにしてSQL文を生成することになります。
String sql = "insert into bookmark(title, url, comment, nickname, password) values" + "('" + MyUtil.SQLEscape(title) + "', '" + MyUtil.SQLEscape(url) + "', '" + MyUtil.SQLEscape(comment) + "', '" + nickname + "', '" + password + "')";
以上で、特殊な文字への対応が完了しました。
これにより、以下の画面のような、例えば「!"#$%&'()=-~^\|[{`@}]*:+;?/>.<」というような、とても入力してほしくないような文字列もコメントとして登録できるようになりました。
Copyright © ITmedia, Inc. All Rights Reserved.