連載
» 2013年12月17日 18時00分 公開

HTML5時代の「新しいセキュリティ・エチケット」(2):単純ではない、最新「クロスサイトスクリプティング」事情 (2/3)

[はせがわようすけ(ネットエージェント株式会社),@IT]

DOM Based XSSの増加

 従来サーバー上だけで生成していたHTMLを、Ajaxなどと組み合わせブラウザー上でJavaScriptによって操作する機会が増えたため、JavaScriptによるDOM操作時に発生するXSS、すなわちDOM Based XSSが急増しています。

【関連記事】

IPAが「DOM Based XSS」の脆弱性に関するレポートを公開

http://www.atmarkit.co.jp/ait/articles/1301/29/news155.html


 DOM Based XSSにおいて、攻撃者によってスクリプトが含まれる可能性のある箇所を「ソース」、JavaScriptプログラム内でそのソースを用いることによって実際にXSSが発生する原因となる機能のことを「シンク」と一部の研究者は呼んでいます。

 実際にソースとして働く機能の例としては以下のようなものがあります。

location.href

location.search

location.hash

document.cookie

document.referrer

window.name

localStorage

sessionStorage


 シンクとして働く機能の例としては以下のようなものがあります。

document.write

element.innerHTML

eval

setTimeout

setInterval

jQuery(),$(), $.html()


 もちろんこれらは代表的な例であり、ソース、シンクともこれら以外にもさまざまなものがあります。必ずしもこの「ソース」「シンク」という用語を覚えておく必要はありませんが、DOM Based XSSに関する理解を深めるためには役に立ちますので紹介しました。

 DOM Based XSSへの具体的な対策としては、(1) 使用しているJavaScriptライブラリの適切なバージョンアップに加え、(2)DOM操作APIの適切な使用、(3)扱うURLをhttpおよびhttpsに限定する、の3点になります。

  • (1) 使用しているJavaScriptライブラリの更新

 現在多くのWebサイトではjQueryをはじめ、多数のJavaScriptライブラリが使用されていますが、これらのライブラリについても脆弱性が発見、報告されることがあります。

 サイトを構築後も、JavaScriptライブラリにセキュリティ修正を行ったバージョンがリリースされた場合には、サイトで利用しているライブラリを更新する必要があります。

  • (2) DOM操作APIの適切な使用

 DOM Based XSSは、JavaScript上でHTMLを組み立てる場合に、攻撃者の用意した文字列がHTML内にそのまま挿入されることによって発生するXSSです。

 DOM Based XSSにおいても、XSS対策の原則である「HTML生成時におけるエスケープ」に従い、シンクへ文字列を与える時点でエスケープ処理を行うという方法は有効ですが、可能であれば文字列を操作するのではなく、DOMを通じてHTMLを生成、操作する方が、原理的にXSSの発生を抑えやすくできます。

 例えば、DOM Based XSSを発生させる典型的なコードの例として、以下のようなinnerHTMLの使用があったとします。

// ★★★脆弱なコードの例★★★
var div = document.getElementById( "msg" );
div.innerHTML = some_text; // 外部からコントロール可能な文字列

 これに対して、従来サーバー側で行われてきた文字列をエスケープするという方法をそのままブラウザー上で行うと以下のようになります。

// 安全なコードの例。★★★決して最適な方法ではない(後述)★★★
function escape_html( s ){
    return s.replace( /&/g, "&" )
       .replace( /</g, "&lt;" )
       .replace( />/g, "&gt;" )
       .replace( /"/g, "&quot;" )
       .replace( /'/g, "&#x27;" );
}
var div = document.getElementById( "msg" );
// some_text は外部からコントロール可能な文字列
div.innerHTML = escape_html( some_text ); 

 この方法でも安全にはなりますが、自由にDOMを操作できるブラウザー上のJavaScriptであれば、DOM APIを経由して操作する方が、原理的に確実にXSSの発生を抑えやすく、またより自然で見通しのよいコードにもなります。

// ★★★安全なコードの例(推奨)★★★
var div = document.getElementById( "msg" );
// some_text は外部からコントロール可能な文字列
var text = document.createTextNode( some_text );
div.appendChild( text );

 jQueryであれば、$( selector ).html( some_text ); ではなく、$( selector ).text( some_text )を使うことになります。

 テキストノードだけでなく、属性についても同様にDOM APIを経由して操作することが望ましいといえます。

// ★★★脆弱な例★★★
var div = document.getElementById( "msg" );
var url = "http://example.jp/" + some_page;   // some_page は外部からコントロール可能な文字列
div.innerHTML = '<a href="' + url + '">' + url + "</a>";
// ★★★安全な例★★★
var div = document.getElementById( "msg" );
var url = "http://example.jp/" + some_page;   // some_page は外部からコントロール可能な文字列
var elm = document.createElement( "a" );
elm.setAttribute( "href", url );
elm.appendChild( document.createTextNode( url ) );
div.appendChild( elm );

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。