あらかじめ定まった構造のHTMLをJavaScriptにて生成し, その一部にデータを当てはめる
たとえば
具体例として,
// bad code
/*
変数friendsには以下のような配列が格納されている
[
{
"name" : "山田太郎",
"mail" : "yamada@example1.jp",
"birthday" : "1980-05-19"
},
{
"name" : "鈴木一郎",
"mail" : "suzuki@example2.jp",
"birthday" : "1991-10-22"
},
{
"name" : "John Smith",
"mail" : "john@example3.jp",
"birthday" : "1993-3-27"
}
]
*/
function expandTemplate (template, friends) {
// テンプレート文字列中の「%name%」「%birthday%」「%mail%」をそれぞれ変数に置換する関数
var i, s, html = "";
for (i = 0; i < friends.length; i++) {
s = template.replace(/%(\w+)%/g, function (s, param) {
if (param === "name") return friends[ i ].name;
else if (param === "birthday") return friends[ i ].birthday;
else if (param === "mail") return friends[ i ].mail;
else return "%" + param + "%";
});
html += s;
}
return html;
}
var template = '<div>%name% さん<br>メールアドレス:<a href="mailto:%mail%">%mail%</a> 誕生日:%birthday%</div>';
var elm = document.getElementById("contacts");
var html = expandTemplate(template, friends);
elm.innerHTML = html;
このようなコードでは,
{
"name" : "<img src=# onerror=alert(1)>",
"mail" : "\"onmouseover=alert(2)//\"@example.jp",
"birthday" : "2000-01-01"
}
攻撃者のこのようなコンタクト先が,
<div><img src=# onerror=alert(1)> さん<br>メールアドレス:<a href="mailto:"onmouseover=alert(2)//"@example.jp">"onmouseover=alert(2)//"@example.jp</a> 誕生日:2000-01-01</div>
このような処理でのDOM-basedの発生を防ぐ最もかんたんな方法は,
function htmlEscape (s) {
s = s.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
return s;
}
function expandTemplate (template, friends){
var i, s, html = "";
for (i = 0; i < friends.length; i++){
s = template.replace( /%(\w+)%/g, function(s, param){
if (param === "name") return htmlEscape(friends[ i ].name);
else if (param === "birthday") return htmlEscape( friends[ i ].birthday);
else if (param === "mail") return htmlEscape(friends[ i ].mail);
else return "%" + param + "%";
});
html += s;
}
return html;
}
このように,
先ほどの例と同様,
{
"name" : "<img src=# onerror=alert(1)>",
"mail" : "\"onmouseover=alert(2)//\"@example.jp",
"birthday" : "2000-01-01"
}
この場合であっても,
<div><img src=# onerror=alert(1)> さん<br>メールアドレス:<a href="mailto:"onmouseover=alert(2)//"example.jp">"onmouseover=alert(2)//"example.jp</a> 誕生日:2000-01-01</div>
先にも述べたように,
- 自動的にエスケープされた値が埋め込まれるのか
- 明示的に指定した場合にのみエスケープされるのか
といった点は確認しておく必要があります。
また,