SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

OWASPでビルトイン・セキュリティ

クロスサイトスクリプティング対策 ホンキのキホン

OWASPでビルトイン・セキュリティ 第3回


XSSの対策

 ここまで説明してきたとおり、XSSが発生する原因は以下の3種類が大部分を占めています。

  1. テキストノードに出力する際の「<」「>」のエスケープ漏れ
  2. 属性値に出力する際の「"」「'」のエスケープ漏れ
  3. URLをリンクとして取り扱う際のプロトコルスキームの確認漏れ

 1.および2.はエスケープ漏れがXSSの原因であることは自明なので、HTMLとして出力する際にこれらをエスケープします。エスケープすべき対象は以下の5文字です。

< > " ' &

 「&」は直接XSSの原因になるわけではありませんが、この文字をエスケープしなければユーザーから入力された「&」を正しく表示できませんので、エスケープが必要です。

 また、2.についてはエスケープに加えて、属性値を必ず「"」または「'」で囲むようにします。そうでなければ、"や'をエスケープしていたとしてもXSSの発生につながることがあるからです。

 多くのプログラミング言語やWebアプリケーション作成用のフレームワークでは、HTMLに出力するために、これらの文字を適切にエスケープする関数があらかじめ用意されていることが多いでしょう。

 PHPであればhtmlspecialchars関数がそれにあたります。

<?php
    // GETで与えられたitemパラメータを取得
    $item = $_GET[ 'item' ];

    // さまざまな処理
    ……
?>
<body>
    <!-- itemをエスケープしてHTML内のテキストノードに出力 -->
    <span><?php echo htmlspecialchars( $item, ENT_QUOTES, 'UTF-8' ); ?></span>
    ……

    <!-- itemをエスケープしてHTML内の属性値に出力 -->
    検索文字列: <input type="text" name="item" value="<?php echo htmlspecialchars( $item, ENT_QUOTES, 'UTF-8' ); ?>">
</body>

 エスケープするのは、HTMLとして出力する直前です。外部から入力された文字列を受け取った直後にエスケープしてしまうと、その後その文字列を用いてさまざまな処理、例えば文字列の文字数に依存しているなどの処理を行う際に問題が発生しやすくなるからです。必ず、「HTMLとして出力する直前にエスケープ」を原則としましょう。

 3.については、URLをリンクとして出力する際にはスキームがhttpあるいはhttpsであること、すなわちURLが「http://」または「https://」で始まることを確認するようにします。場合によっては「/foo」のように「/」で始まるURLを許容してもよいでしょう(注2)。

 決して、javascript:スキームであればNG、のような確認を行わないようにしてください。XSSが発生するのはjavascript:スキームだけでなくvbscript:スキームを始め複数の種類があるため、「httpやhttpsのように安全なものだけを許可する」という方針のほうが堅実だからです。

 例えば、PHPであれば以下のように正規表現を用いて文字列の先頭が「http://」「https://」あるいは「/」であることを確認し、そうである場合にのみa要素のhref属性にURLを設定することで、リンクによるXSSを防ぐことができます。

<?php
    function checkUrl( $url ){
        if( preg_match( "/\Ahttps?:\/\//", $url ) || preg_match( "/\A\//", $url ) ){
            return $url;
        }else{
            return "";
        }
    }
?>
……
<div>
    <a href="<?php echo htmlspecialchars( checkUrl( $url ), ENT_QUOTES, 'UTF-8' ); ?>">
        <?php echo htmlspecialchars( $url, ENT_QUOTES, 'UTF-8' ); ?></a>
</div>

 ここでもa要素のhref属性の属性値として出力していますので、先ほど同様にhtmlspecialcharsによるエスケープを忘れてはいけません。

注2

 攻撃者の指定したURLをリダイレクト先として用いる場合には、リダイレクト先が許可されたドメインであるかを確認し、オープンリダイレクタと呼ばれる脆弱性を防ぐ必要があります。オープンリダイレクタについての説明は本稿の範囲を超えますので今回は割愛します。

まとめ

 ここまで解説したとおり、XSSの対策として有効な基本的なルールは以下のようなものになります。

  • テキストノードや属性値としてHTMLを出力する時点で「<」「>」「"」「'」「&」の5文字をエスケープする
  • 属性値は引用符で囲む
  • URLをリンクとして取り扱う場合にはhttpおよびhttpsスキームに限定する

 これですべてのXSSが防げるわけではありませんが、現実に発生しているXSSの多くはこのルールを徹底することで防げるものが大半です。

 本稿では、XSSの原理と対策の基本について解説を行いました。

 一方、XSSは攻撃の種類や発生箇所が多岐にわたるため、本稿だけではカバーできていない内容も多数あります。それらについては先に紹介したXSS (Cross Site Scripting) Prevention Cheat Sheetなどを活用してみてください。また、近年はJavaScriptによるクライアント側でのコード量が増えたことによって、JavaScript上で発生するDOM Based XSSと呼ばれる種類のXSSも増加しています。これについてはDOM based XSS Prevention Cheat Sheetなどを参考にしてみてください。

 本稿がセキュアなWebアプリケーション構築の一助になれば幸いです。

修正履歴

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
OWASPでビルトイン・セキュリティ連載記事一覧

もっと読む

この記事の著者

はせがわようすけ(OWASP Kansai)(ハセガワ ヨウスケ)

OWASP Kansai Chapter Leader、OWASP Japan Technical Board Member として国内でのOWASPの活動に寄与。 Internet Explorer、Mozilla FirefoxをはじめWebアプリケーションに関する多数の脆弱性を発見。 Blac...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/9149 2015/12/28 20:41

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー