XSSの発生する原因
先ほどの例では、テキストとして表示されるべき部分(テキストノード)に攻撃者によって与えられた「<」や「>」がエスケープされず、そのまま埋め込まれたためにHTMLのタグとして扱われることでXSSが発生しましたが、それ以外にもXSSが発生する原因としてよくあるのは、属性値へ出力する際に「"」や「'」がエスケープされていないというものです。
前述と同じく、http://shop.example.jp/search?item=OWASPというURLにアクセスすることで「OWASP」を含む商品一覧を表示するショッピングサイトがあり、そこではレスポンスとして返されるHTMLの一部にinput要素のvalue属性の値としてURLのitemパラメータで指定された「OWASP」という文字列が含まれていたとします。
<form method="GET" action="/search"> 検索文字列: <input type="text" name="item" value="OWASP"> <input type="submit" vaue="検索"> </form>
このときに、攻撃者が検索文字列として「" onmouseover="alert('hacked!')」という文字列を与えた場合に、サーバ側が以下のようなHTMLを返したとします。
<form method="GET" action="/search"> 検索文字列: <input type="text" name="item" value="" onmouseover="alert('hacked!')"> <input type="submit" vaue="検索"> </form>
そうすると、input要素中ではvalue属性は空になり、onmouseover属性によってマウス移動時のイベントハンドラが設定されたHTMLとしてブラウザには解釈されます。
攻撃者によって誘導された利用者がブラウザでこのURLを開くと、onmouseoverイベントハンドラが有効であるために、input要素の上でマウスを動かした瞬間にブラウザ内で攻撃者の作成したJavaScriptが動作してしまいます。
このように、テキストノードでは「<」「>」がエスケープされていないためにXSSが発生しましたが、属性値への出力では「"」(HTMLの書き方によっては「'」の場合もあり得ます)のエスケープがなされていないためにXSSが発生しました。
また、テキストノードと属性値以外にも、リンク先として設定されるURLにjavascript:スキームなどが埋め込まれた場合にもXSSが発生します。
例えば、自身のプロフィールの設定として任意のURLを登録できるSNSがあったとします。他の利用者がその人物のプロフィールページを表示させたときには、URLは自動的にリンクとしてa要素となるといったものです。
<div> <a href="https://www.owasp.org/index.php/Kansai">https://www.owasp.org/index.php/Kansai</a> </div>
このような場合に、攻撃者が自身のプロフィールにURLとして「javascript:alert('hacked!')」といった文字列を設定した場合に、以下のようにそのままa要素のhref属性にこの文字列が設定されるとどうなるでしょうか。
<a href="javascript:alert('hacked!')">javascript:alert('hacked!')</a>
この攻撃者のプロフィールページを一般の利用者が閲覧し、そのときにリンク先のURLをクリックしてしまうと、攻撃者の作成したJavaScriptが利用者のブラウザ上で動作してしまいます。
このように、攻撃者が与えたURLによってリンクを生成する場合にjavascript:スキームなどを許容していると、エスケープ漏れの場合と同様にXSSが発生することになってしまいます。