パラメータの偽装に備える
では、テキストの入力以外のフォームでは、こうした注意は不要でしょうか。例えば、ラジオボタンを使ったフォームの場合を考えてみましょう。
<%
request.setCharacterEncoding("UTF-8");
String rd = request.getParameter("radio1");
out.println("あなたは、" + rd + "を選びました。<br>");
%>
※送信フォーム<br>
<form method="post" action="index.jsp">
<input type="radio" name="radio1" value="A" checked>ラジオ1
<input type="radio" name="radio1" value="B">ラジオ2
<br><input type="submit">
</form>>
JSPタグと送信フォームの部分のみで、それ以外の部分は省略しました。これは、radio1という名前のラジオボタンをフォームから送信し、選択した項目を表示するサンプルです。こうした「テキストの入力がないフォーム」の場合、XSSのような心配は要らない、と多くの人は考えてしまいがちです。が、そうでしょうか?
では、ここでちょっとした実験をしてみましょう。ブラウザのアドレスバーから、直接URLを入力してページにアクセスしてみることにします。このサンプルページが、http://localhost:8080/webapp1/index.jspというURLだと仮定した場合、以下のようにアドレスを入力し実行してみましょう。
http://localhost:8080/webapp1/index.jsp?radio1=%3Cscript%20
language=javascript%3Ealert(navigator.userAgent);%3C/script%3E
アドレスバーから直接URLを送信することでパラメータを偽装しスクリプトを実行できる。 |
見やすいように改行してありますが、実際には1行の文としてアドレスに記述します。これを実行すると、先ほどと同じように画面にアラートが現れ、現在のブラウザの種類の情報が表示されます。URLにパラメータに関する情報を付加して送信することで、送信内容を偽装していたのです。
フォームの送信には、通常「GET」と「POST」が用いられます。GETの場合、送信内容を「URLエンコード」と呼ばれる方式でエンコードし、URLの後に&記号でつけて送られます。POSTの場合、実際にHTTPサーバとやり取りする中で送信内容が送られます。このため、GETによる送信は、直接URLに送信内容の情報を付け加えて送ることで送信内容を偽装できるのです。
「ちょっと待った!さっきのフォームはPOSTだったはずだ」と思った人。その通り、先のサンプルではPOSTを使って送信をしていました。が、JSPのrequest.getParameterで送信内容を受け取る場合、指定の名前のパラメータがあれば、GETでもPOSTでも関係なく値を取り出せてしまうようになっています。つまり、フォーム自体をPOSTで作ってあっても、GETの方式でパラメータを偽装して送ればちゃんとプログラムは動いてしまうのです。
ラジオボタンといえども、このように値を偽装して送れてしまうのですから、ちゃんとXSS対策をとっておくべきです。ラジオボタンなどは「必要な値以外は受け付けない」ようにしてもよいのですが、先ほどと同じようにreplaceAllでタグを置換しても問題は回避できます。
<%
request.setCharacterEncoding("UTF-8");
String rd = request.getParameter("radio1");
// タグの処理
rd = rd.replaceAll("<","<");
rd = rd.replaceAll(">",">");
out.println("あなたは、" + rd + "を選びました。<br>");
%>
タグを置換することでパラメータ偽装も防ぐことができる。 |
これで、パラメータを偽装して送信されてもスクリプトが実行される心配はなくなります。ラジオボタンに限らず、チェックボックス、選択リストなども同様の「パラメータ偽装」がなされることが考えられますので、同じような対処が必要です。
今回とりあげたXSSは、Webサイトへの、主に個人情報の盗用を目的とした攻撃ですが、この他にもさまざまな攻撃がWebサイトには仕掛けられます。最初からそのすべてに対応するのは難しいでしょうが、「こうした攻撃に晒されても問題なく動くシステムを作るのがプログラマの仕事なのだ」ということは忘れないようにしましょう。