クロスサイトスクリプティング
日本語 | 画面交差台本実行 |
英語 | cross-site scripting |
ふりがな | くろすさいとすくりぷてぃんぐ |
フリガナ | クロスサイトスクリプティング |
セキュリティホールのひとつ。
Webサービス等において、ある人が入力した情報を他の人が表示した時に、HTMLの構造を変え、JavaScriptの実行等により個人情報の取得等の被害をもたらすこと。
「XSS」と略される。
クロスサイトスクリプティングは、「ある人の入力した情報が、他の人にも見られる」という場合に発生しうる。
たとえば、もしこのJavaA2Zに「最近検索された単語一覧」のような画面があるとする。検索文字列をデータベースに貯え、それを一覧表示する、という画面とする。
ある人「A」が、検索文字列に「あい<BR>うえお」と入力したとする。もしこの検索文字列をそのまま「最近検索された単語一覧」に表示する、という仕様の場合、ある人「B」がそれを見ると、「あい<BR>うえお」は「あい(改行)うえお」と、意図しない改行が行われて表示される。
つまり、「A」が画面(Webサイト)で入力した情報が「B」の画面(Webサイト)へと、画面(Webサイト)をまたいで(クロス)表示されることになる。
もしこれが、JavaScriptのプログラムを含む場合、プログラムが実行され(スクリプティング)、個人情報の抜き出しや意図しない操作の強制等が行われることになる。
これが、「クロスサイトスクリプティング」である。
他人が入力した情報が「HTMLの構造を変え、JavaScriptを実行させる」ものだった場合、それが自分の画面に表示される際に実行されてしまう、これが「クロスサイトスクリプティング」という脆弱性である。
クロスサイトスクリプティングを防ぐ方法は、「出力時にタグを無効化する」というものである。
これを「サニタイジング」という。
具体的には、HTMLタグの前後にある「<」「>」を、実体参照である「<」「>」に置き換える、といったものである。そうすることで、HTMLタグを出力できないようにする。
さらに安全を期すために、「&」「"」「'」等も変換することが多い。
これらの変換によって、HTMLの構造は変えられず、JavaScriptも実行されない。
ただし、実際にはそう容易ではない。
なぜならこの場合、HTMLタグは完全に無効化されてしまうためである。
出力する内容によっては、サニタイジングしていいHTMLタグとしてはいけないHTMLタグが存在することになる。通常のHTMLタグはサニタイジングするが、<A HREF>タグはサニタイジングしない、といった複雑なルールが作られることになる。
これをプログラムで処理するとなると、HTMLの解析が必要になるなど、処理が複雑になり、これが結果としてクロスサイトスクリプティングを生む場合もある。
Webサービス等において、ある人が入力した情報を他の人が表示した時に、HTMLの構造を変え、JavaScriptの実行等により個人情報の取得等の被害をもたらすこと。
「XSS」と略される。
クロスサイトスクリプティングは、「ある人の入力した情報が、他の人にも見られる」という場合に発生しうる。
たとえば、もしこのJavaA2Zに「最近検索された単語一覧」のような画面があるとする。検索文字列をデータベースに貯え、それを一覧表示する、という画面とする。
ある人「A」が、検索文字列に「あい<BR>うえお」と入力したとする。もしこの検索文字列をそのまま「最近検索された単語一覧」に表示する、という仕様の場合、ある人「B」がそれを見ると、「あい<BR>うえお」は「あい(改行)うえお」と、意図しない改行が行われて表示される。
つまり、「A」が画面(Webサイト)で入力した情報が「B」の画面(Webサイト)へと、画面(Webサイト)をまたいで(クロス)表示されることになる。
もしこれが、JavaScriptのプログラムを含む場合、プログラムが実行され(スクリプティング)、個人情報の抜き出しや意図しない操作の強制等が行われることになる。
これが、「クロスサイトスクリプティング」である。
他人が入力した情報が「HTMLの構造を変え、JavaScriptを実行させる」ものだった場合、それが自分の画面に表示される際に実行されてしまう、これが「クロスサイトスクリプティング」という脆弱性である。
クロスサイトスクリプティングを防ぐ方法は、「出力時にタグを無効化する」というものである。
これを「サニタイジング」という。
具体的には、HTMLタグの前後にある「<」「>」を、実体参照である「<」「>」に置き換える、といったものである。そうすることで、HTMLタグを出力できないようにする。
さらに安全を期すために、「&」「"」「'」等も変換することが多い。
これらの変換によって、HTMLの構造は変えられず、JavaScriptも実行されない。
ただし、実際にはそう容易ではない。
なぜならこの場合、HTMLタグは完全に無効化されてしまうためである。
出力する内容によっては、サニタイジングしていいHTMLタグとしてはいけないHTMLタグが存在することになる。通常のHTMLタグはサニタイジングするが、<A HREF>タグはサニタイジングしない、といった複雑なルールが作られることになる。
これをプログラムで処理するとなると、HTMLの解析が必要になるなど、処理が複雑になり、これが結果としてクロスサイトスクリプティングを生む場合もある。
参考サイト
- (参考サイトはありません)
<!-- webapps/sample-servlet/form.html -->
<!-- http://localhost:8080/sample-servlet/form.html でアクセスできます。 --><HTML>
<HEAD>
<TITLE>入力フォーム</TITLE>
</HEAD>
<BODY>
<!-- 入力フォームです。 -->
<FORM METHOD="POST" ACTION="servlet/SampleServlet">
名前:<INPUT TYPE="text" NAME="name" SIZE="10"><BR>
<INPUT TYPE="submit" VALUE="実行"><BR>
</FORM>
</BODY>
</HTML>
// webapps/sample-servlet/WEB-INF/src/SampleServlet.java
// http://localhost:8080/sample-servlet/servlet/SampleServlet でアクセスできます。
// このサンプルプログラムは「サーブレット」の項目に書かれている準備を行ってから使用してください。
import java.util.ArrayList;
import java.util.Iterator;
import java.io.PrintWriter;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* サーブレットのテスト。
*/
public class SampleServlet extends HttpServlet
{
/** 「お名前一覧」用リスト。 */
private static final ArrayList names = new ArrayList();
/**
* リクエストとしてHTTPメソッドのGETが渡されるとこのメソッドが呼ばれます。
*/
public void doGet( HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException
{
// Content-Typeをセット。
response.setContentType( "text/html;charset=Windows-31J" );
// 入力値の文字コードをセットします。
// HTMLの文字コードを指定してください。
request.setCharacterEncoding( "Windows-31J" );
// 入力フォームから入力された値を取得します。
String name = request.getParameter( "name" );
System.out.println( name );
// (入力フォームの「名前:」に入力された文字列)
// 入力された名前を追加します。
if( ( name != null ) && ( name.equals( "" ) == false ) )
{
names.add( name );
}
// 注:通常は、データベースに登録します。
// また、この方法だと同期が取れていませんので、複数のブラウザで
// 同時にアクセスするとうまくいかないでしょう。
// HTML出力用のPrintWriterを取得します。
PrintWriter out = response.getWriter();
// HTMLを出力します。
out.println( "<HTML>" );
out.println( "<HEAD>" );
out.println( "<TITLE>サーブレットのテスト</TITLE>" );
out.println( "</HEAD>" );
out.println( "<BODY>" );
out.println( "入力された値:" );
out.println( name );
out.println( "<BR>" );
// 名前一覧を出力します。
for( Iterator iter = names.iterator(); iter.hasNext(); )
{
String currentName = (String)iter.next();
out.println( currentName );
out.println( "<BR>" );
}
// これが、クロスサイトスクリプティングという脆弱性です。
// もし、入力された名前にHTMLタグやJavaScriptのプログラムが書き込まれていたら、
// それがそのまま出力されてしまいます。
// たとえば「あい<BR>うえお」と入力すると、途中で改行されます。
// このように、他の人が記入した内容をそのまま出力してしまい、
// 出力結果が意図しない形で改竄され、さらにJavaScriptプログラムが実行されて
// 個人情報が盗まれる等の被害が出る可能性があるのが、クロスサイトスクリプティング
// です。
// この問題を回避するために、画面への出力前に変換します。
// 変換は、主に「<を<に置換」といった処理を行います。
// これを「サニタイジング」と言います。
// ただし、「通常のタグは不可だけど、<A HREF>タグだけは使用したい、
// といった場合には処理が面倒になり、そういったところのバグから
// クロスサイトスクリプティングが発生することもあります。
out.println( "</BODY>" );
out.println( "</HTML>" );
}
/**
* リクエストとしてHTTPメソッドのGETが渡されるとこのメソッドが呼ばれます。
*/
protected void doPost( HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException
{
// でも面倒なのでdoGet()メソッドに丸投げします。
doGet( request, response );
}
}
<!-- http://localhost:8080/sample-servlet/form.html でアクセスできます。 --><HTML>
<HEAD>
<TITLE>入力フォーム</TITLE>
</HEAD>
<BODY>
<!-- 入力フォームです。 -->
<FORM METHOD="POST" ACTION="servlet/SampleServlet">
名前:<INPUT TYPE="text" NAME="name" SIZE="10"><BR>
<INPUT TYPE="submit" VALUE="実行"><BR>
</FORM>
</BODY>
</HTML>
// webapps/sample-servlet/WEB-INF/src/SampleServlet.java
// http://localhost:8080/sample-servlet/servlet/SampleServlet でアクセスできます。
// このサンプルプログラムは「サーブレット」の項目に書かれている準備を行ってから使用してください。
import java.util.ArrayList;
import java.util.Iterator;
import java.io.PrintWriter;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* サーブレットのテスト。
*/
public class SampleServlet extends HttpServlet
{
/** 「お名前一覧」用リスト。 */
private static final ArrayList names = new ArrayList();
/**
* リクエストとしてHTTPメソッドのGETが渡されるとこのメソッドが呼ばれます。
*/
public void doGet( HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException
{
// Content-Typeをセット。
response.setContentType( "text/html;charset=Windows-31J" );
// 入力値の文字コードをセットします。
// HTMLの文字コードを指定してください。
request.setCharacterEncoding( "Windows-31J" );
// 入力フォームから入力された値を取得します。
String name = request.getParameter( "name" );
System.out.println( name );
// (入力フォームの「名前:」に入力された文字列)
// 入力された名前を追加します。
if( ( name != null ) && ( name.equals( "" ) == false ) )
{
names.add( name );
}
// 注:通常は、データベースに登録します。
// また、この方法だと同期が取れていませんので、複数のブラウザで
// 同時にアクセスするとうまくいかないでしょう。
// HTML出力用のPrintWriterを取得します。
PrintWriter out = response.getWriter();
// HTMLを出力します。
out.println( "<HTML>" );
out.println( "<HEAD>" );
out.println( "<TITLE>サーブレットのテスト</TITLE>" );
out.println( "</HEAD>" );
out.println( "<BODY>" );
out.println( "入力された値:" );
out.println( name );
out.println( "<BR>" );
// 名前一覧を出力します。
for( Iterator iter = names.iterator(); iter.hasNext(); )
{
String currentName = (String)iter.next();
out.println( currentName );
out.println( "<BR>" );
}
// これが、クロスサイトスクリプティングという脆弱性です。
// もし、入力された名前にHTMLタグやJavaScriptのプログラムが書き込まれていたら、
// それがそのまま出力されてしまいます。
// たとえば「あい<BR>うえお」と入力すると、途中で改行されます。
// このように、他の人が記入した内容をそのまま出力してしまい、
// 出力結果が意図しない形で改竄され、さらにJavaScriptプログラムが実行されて
// 個人情報が盗まれる等の被害が出る可能性があるのが、クロスサイトスクリプティング
// です。
// この問題を回避するために、画面への出力前に変換します。
// 変換は、主に「<を<に置換」といった処理を行います。
// これを「サニタイジング」と言います。
// ただし、「通常のタグは不可だけど、<A HREF>タグだけは使用したい、
// といった場合には処理が面倒になり、そういったところのバグから
// クロスサイトスクリプティングが発生することもあります。
out.println( "</BODY>" );
out.println( "</HTML>" );
}
/**
* リクエストとしてHTTPメソッドのGETが渡されるとこのメソッドが呼ばれます。
*/
protected void doPost( HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException
{
// でも面倒なのでdoGet()メソッドに丸投げします。
doGet( request, response );
}
}
<!-- webapps/sample-servlet/form.html --> <!-- http://localhost:8080/sample-servlet/form.html でアクセスできます。 --><HTML> <HEAD> <TITLE>入力フォーム</TITLE> </HEAD> <BODY> <!-- 入力フォームです。 --> <FORM METHOD="POST" ACTION="servlet/SampleServlet"> 名前:<INPUT TYPE="text" NAME="name" SIZE="10"><BR> <INPUT TYPE="submit" VALUE="実行"><BR> </FORM> </BODY> </HTML> // webapps/sample-servlet/WEB-INF/src/SampleServlet.java // http://localhost:8080/sample-servlet/servlet/SampleServlet でアクセスできます。 // このサンプルプログラムは「サーブレット」の項目に書かれている準備を行ってから使用してください。 import java.util.ArrayList; import java.util.Iterator; import java.io.PrintWriter; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * サーブレットのテスト。 */ public class SampleServlet extends HttpServlet { /** 「お名前一覧」用リスト。 */ private static final ArrayList names = new ArrayList(); /** * リクエストとしてHTTPメソッドのGETが渡されるとこのメソッドが呼ばれます。 */ public void doGet( HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException { // Content-Typeをセット。 response.setContentType( "text/html;charset=Windows-31J" ); // 入力値の文字コードをセットします。 // HTMLの文字コードを指定してください。 request.setCharacterEncoding( "Windows-31J" ); // 入力フォームから入力された値を取得します。 String name = request.getParameter( "name" ); System.out.println( name ); // (入力フォームの「名前:」に入力された文字列) // 入力された名前を追加します。 if( ( name != null ) && ( name.equals( "" ) == false ) ) { names.add( name ); } // 注:通常は、データベースに登録します。 // また、この方法だと同期が取れていませんので、複数のブラウザで // 同時にアクセスするとうまくいかないでしょう。 // HTML出力用のPrintWriterを取得します。 PrintWriter out = response.getWriter(); // HTMLを出力します。 out.println( "<HTML>" ); out.println( "<HEAD>" ); out.println( "<TITLE>サーブレットのテスト</TITLE>" ); out.println( "</HEAD>" ); out.println( "<BODY>" ); out.println( "入力された値:" ); out.println( name ); out.println( "<BR>" ); // 名前一覧を出力します。 for( Iterator iter = names.iterator(); iter.hasNext(); ) { String currentName = (String)iter.next(); out.println( currentName ); out.println( "<BR>" ); } // これが、クロスサイトスクリプティングという脆弱性です。 // もし、入力された名前にHTMLタグやJavaScriptのプログラムが書き込まれていたら、 // それがそのまま出力されてしまいます。 // たとえば「あい<BR>うえお」と入力すると、途中で改行されます。 // このように、他の人が記入した内容をそのまま出力してしまい、 // 出力結果が意図しない形で改竄され、さらにJavaScriptプログラムが実行されて // 個人情報が盗まれる等の被害が出る可能性があるのが、クロスサイトスクリプティング // です。 // この問題を回避するために、画面への出力前に変換します。 // 変換は、主に「<を<に置換」といった処理を行います。 // これを「サニタイジング」と言います。 // ただし、「通常のタグは不可だけど、<A HREF>タグだけは使用したい、 // といった場合には処理が面倒になり、そういったところのバグから // クロスサイトスクリプティングが発生することもあります。 out.println( "</BODY>" ); out.println( "</HTML>" ); } /** * リクエストとしてHTTPメソッドのGETが渡されるとこのメソッドが呼ばれます。 */ protected void doPost( HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException { // でも面倒なのでdoGet()メソッドに丸投げします。 doGet( request, response ); } }