XSSを引き起こすシンクの事例としてinnerHTMLへのHTMLの代入やlocationオブジェクトへのURLの代入をとりあげました。XSSの原因として見かけるシンクの代表的なものについて説明します。document.write/document.writeln~できるだけ使わず,代替手段を利用するDOMのレンダリングを遅延させるなどの理由から,以前に比べるとdocument.writeの使用される頻度は減っていますが,それでもなお広告用のJavaScriptなど一部では根強くdocument.writeが使われています。以下のようなコードでは,攻撃者が自身のサイトにてhttp://attacker.example.com/?<script>alert(1)</script>のようなページを作り,そこから攻撃対象のサイトへ移動させることで,リファラを経由してXSSを発生させることができます(※1⁠)⁠。XSSの発生を抑える最善の方法は,document.writeを使用しないことです。以下のように,代替となる手段を用いることで,document.writeを使用せずに同様の目的を達成することができます。HTML中に単純に文字列を出力したいのであれば,前回解説したようにdocument.createTextNodeを用いてテキストノードを生成するHTMLを生成するのであれば,document.createElementを用いてDOM操作を行うどうしてもdocument.writeを使わなければいけない場合には,「⁠document.writeで出力するコンテキストに応じて文字列をエスケープする」という,これまでサーバサイドで行っていたXSS対策と同じことをJavaScript上で行う必要があります。テキストノードやHTML要素の属性値に対してdocument.writeを使う場合には,「⁠<」「⁠>」「⁠"」「⁠'」「⁠&」の各文字をエスケープして出力する,ということになります。以下のコードでは,従来サーバ側で行っていたXSS対策と同様に,攻撃者がコントロール可能な変数であるtextおよびurlをdocument.writeへ出力する前にエスケープしています。XSSが発生してしまいます。繰り返しになりますが,DOMへ文字列や要素を追加するのであれば,document.writeを使用するのではなく,DOM操作APIを利用することを推奨します。7や8.1のIEでは,リファラにエンコードされていない「<」や「>」を含めることができます。eval~現在のブラウザならJSON.parseを利用するevalは,引数として与えられた文字列を式として評価,あるいはJavaScriptのステートメントとして実行します。evalの引数に攻撃者がコントロール可能な文字列を渡した場合には,攻撃者が自由にJavaScriptを実行できてしまいます。すると,古い資料などには,JSON文字列をJavaScriptのオブジェクトに変換するためにevalを利用した以下のようなコード例を載せているかもしれません。);しかし,このようなJSON文字列からオブジェクトを生成する場合,現在のブラウザではJSON.parseが利用できるので,evalを呼び出す必要はありません。IE7のように,JSON.parseがサポートされていない古いブラウザをどうしてもサポートしなければいけない場合には,json2.js(https://github.com/douglascrockford/JSON-js/blob/master/json2.js)を読み込むことで同様の機能を利用できます。);そもそも,ほとんどの一般的なプログラムではevalを使う必要性はないでしょう。してもevalを使用しなければならない場合には,引数として攻撃者がコントロール可能な文字列が渡らないようにしましょう。}}setTimeout/setInterval~引数では文字列ではなく関数を渡すようにするsetTimeoutやsetIntervalは,引数で与えられた関数を一定時間後に(setIntervalは一定間隔で繰り返し)実行します。このとき,第1引数に関数の代わりに文字列を与えた場合には,evalと同様,その文字列をJavaScriptとして実行します。以下のようなコードでは,攻撃者が変数textを自由にコントロールできた場合にはsetTimeoutを経由して攻撃者が自由にJavaScriptを実行できてしまいます。1000);そのため,以下のように,setTimeoutやsetIntervalには文字列ではなく関数を渡すようにしましょう。text);なお,このコードではsetTimeoutに追加の引数を与えることでコールバック関数にその引数を渡していますが,この機能はIE9では使用できません。IE9もサポート対象として含めるのであれば,次のようなクロージャを利用したコードを書くといいいでしょう(※2⁠)⁠。);※2)IE9でsetTimeoutやsetIntervalのコールバック関数に引数を渡すための互換用コードがhttps://developer.mozilla.org/ja/docs/Web/API/window.setTimeoutにあります。setTimeoutの呼び出しからalertの実行までの間に変数textが変化しない場合には,必ずしもクロージャは必要ではありません。Function~引数にコントロール可能な文字列が渡らないようにするFunctionコンストラクタを使用すると,文字列からFunctionオブジェクトを生成し,それを呼び出すことができます。以下のようなコードでは,攻撃者が変数textを自由にコントロールできた場合,Functionコンストラクタを通じて攻撃者が自由にJavaScriptを実行できてしまいます。0;");func();そもそも,ほとんどの一般的なプログラムではFunctionコンストラクタを用いて動的にコードを生成する必要性はないでしょう。してもFunctionコンストラクタを使用しなければならない場合には,引数として攻撃者がコントロール可能な文字列が渡らないようにしましょう。jQuery()/$()/$.html()~自分で書くときより挙動が見えにくくなるのでいっそう注意をjQueryは,以前ほどではありませんが今でも広く使用されているJavaScriptライブラリであり,DOMの操作においてもJavaScriptそのままで操作を行うのに比べ便利なAPIを多数提供しています。XSSのシンクとして働く機能が多くあるので,注意が必要です。jQueryのAPIでシンクとして働く代表的な機能としては,jQuery(),$(),$.html()などがあります。XSSが発生することになります。XSSを避けるには,以下のような配慮が必要となります。XSSのシンクとして機能してしまうのかどうかが見えにくくなります。呼び出すAPIがシンクとして機能することがないかの確認や,シンクとして機能するAPIを呼び出す場合には引数となる文字列を攻撃者がコントロールできないようにするといった注意が必要になります。XSSの原因として見かける代表的なシンクを紹介しました。XSS対策について説明します。XSS著者プロフィールはせがわようすけ株式会社セキュアスカイ・テクノロジー常勤技術顧問。FirefoxをはじめWebアプリケーションに関する多数の脆弱性を発見。