JavaScriptセキュリティの基礎知識
第7回 DOM-based XSS その2
前回は,
document. write/ document. writeln~できるだけ使わず, 代替手段を利用する
DOMのレンダリングを遅延させるなどの理由から,
たとえば,
// bad code
document.write(location.referrer);
document.
- HTML中に単純に文字列を出力したいのであれば,
前回解説したようにdocument. createTextNodeを用いてテキストノードを生成する - HTMLを生成するのであれば,
document. createElementを用いてDOM操作を行う
どうしてもdocument.
以下のコードでは,
function htmlEscape(s) {
s = s.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
return s;
}
// 変数text,urlはどちらも攻撃者がコントロール可能な文字列
var html = '<div>' + htmlEscape(text) + '<img src="' + htmlEscape(url) + '" alt="' + htmlEscape(text) + '"></div>';
document.write(html);
当然ながら,
繰り返しになりますが,
- ※1)
- Windows 7や8.
1のIEでは, リファラにエンコードされていない 「<」 や 「>」 を含めることができます。
eval~現在のブラウザならJSON. parseを利用する
evalは,
もしかすると,
// bad code
var json = '{ "name" : "hasegawa", "url" : "http://utf-8.jp/" }';
var obj = eval( "(" + json + ")" );
しかし,
IE7のように,
if (window.JSON === undefined) {
var elm = document.createElement("script");
elm.setAttribute("type", "text/javascript");
elm.setAttribute("src", "json2.js");
document.body.appendChild(elm);
}
/* ... */
var json = '{ "name" : "hasegawa", "url" : "http://utf-8.jp/" }';
var obj = JSON.parse(json );
そもそも,
// 変数textは攻撃者がコントロール可能な文字列
function foo (text) {
var codes = {
"alert" : "alert('Hello from alert');",
"prompt" : "prompt('Enter the tex')",
"confirm" : "confirm('Choose ok or cancel');"
};
if (codes[text] !== undefined) {
eval(codes[text]); // evalには攻撃者がコントロール可能な文字列は渡らない
}
}
setTimeout/ setInterval~引数では文字列ではなく関数を渡すようにする
setTimeoutやsetIntervalは,
// bad code
// 変数 text は攻撃者がコントロール可能な文字列
setTimeout("alert('" + text + "');", 1000);
そのため,
// 変数tex は攻撃者がコントロール可能な文字列
setTimeout(function( s ){ alert( s ); }, 1000, text);
なお,
// 変数textは攻撃者がコントロール可能な文字列
setTimeout(
(function (s){
return function(){ alert(s); };
})(text), 1000
);
- ※2)
- IE9でsetTimeoutやsetIntervalのコールバック関数に引数を渡すための互換用コードがhttps://
developer. mozilla. org/ ja/ docs/ Web/ API/ window. setTimeoutにあります。また, setTimeoutの呼び出しからalertの実行までの間に変数textが変化しない場合には, 必ずしもクロージャは必要ではありません。
Function~引数にコントロール可能な文字列が渡らないようにする
Functionコンストラクタを使用すると,
// bad code
// 変数textは攻撃者がコントロール可能な文字列
var func = new Function("alert('" + text + "'); return 0;");
func();
そもそも,
jQuery()/ $()/ $.html()~自分で書くときより挙動が見えにくくなるのでいっそう注意を
jQueryは,
jQueryのAPIでシンクとして働く代表的な機能としては,
// bad code
// 変数textは攻撃者がコントロール可能な文字列
$("#element").html(text); // 通常のinnerHTMLと同様に任意のHTMLが生成される
$(text).append("<div>news</div>"); // textに「<img src=# onerror='alert(1)'>」などが設定されるとスクリプトとして実行される
jQueryを使う場合にDOM-based XSSを避けるには,
- $.html()ではなく,
$.text()を使う - $()へ渡すセレクタは,
攻撃者がコントロールできないようにする
jQueryに限った話ではありませんが,
今回は,
次回は,