クロスサイト・リクエスト・フォージェリーを防ぐ: ブラウザーのタブに潜む危険を認識する

クロスサイト・リクエスト・フォージェリーを防ぐ方法を学んでおかなければ、いつのまにかクライアントがハッカーの命令を実行してしまう恐れがあります

この記事では、クロスサイト・リクエスト・フォージェリー攻撃の詳細なシナリオをステップバイステップで確認しながら、クロスサイト・リクエスト・フォージェリー攻撃を防ぐ 2 つの戦略を探ります。また、スキャン・ツールを使用してクロスサイト・リクエスト・フォージェリーの脆弱性を探す際の問題についても見て行きます。

Paul Ionescu, Secure Engineering Program Coordinator, IBM

Photo of Paul IonescuPaul Ionescu は、IBM Security Systems 部門のセキュア・エンジニアリング・プログラムのリーダーであり、AppScan Research and Devlopemnt チームの一員でもあります。IBM で働くようになった 2007年以降、彼はサポート、テクニカル・セールス、テクニカル・イネーブルメント、開発などを含むアプリケーション・セキュリティー・ビジネスのいくつかの分野に携わりました。



2014年 6月 26日

はじめに

IBM Security AppScan Standard

IBM Security AppScan Standard は、アプリケーションに潜在する、XSRF に対する脆弱性を見つけるのに役立つ製品です。developerWorks から IBM Security AppScan Standard の評価版をダウンロードして試してください。

皆さんはたまに、自分が忘れっぽくなってきているのではないかと思うことがあるのではないでしょうか?例えば、「自分のソーシャル・ネットワーキング・アカウントで、このサイトへのリンクを張ったのはいつだろう?」と自問したりする場合があるかもしれません。人によっては、それに気付かずに、友達からソーシャル・ネットワーキング・アカウントにアダルト・サイトへのリンクが送られてきたと突然聞かされて、初めてそのことを知ることさえあります。

結局のところ、ブラウザーのタブに開いた Web サイトが、あなたに代わってアクションを実行することはあり得る話なのです。

例えば、あなたがブラウザーの 1 つ目のタブにソーシャル・ネットワーキング・サイトを開いて、2 つ目のタブに many_ads.com という別のサイトを開いたとします。あなたは知りませんが、この many_ads.com は悪質なサイトです。many_ads.com サイトからは、1 つ目のタブに開かれたソーシャル・ネットワーキング・サイトにメッセージを投稿することができます。このアクションが、クロスサイト・リクエスト・フォージェリー (略して XSRF または CSRF) と呼ばれるものです。

悪質な投稿は不快で気恥ずかしいものですが、取り返しがつかないというほどの問題ではないですよね?なぜなら、その投稿はいつでも削除できるからです。

しかし、XSRF 攻撃は金銭的な被害を及ぼすこともあります。あなたの銀行のサイトが XSRF 攻撃に対して脆弱だったとしたら、あなたの口座から知らない海外の口座に送金される可能性も考えられます。それは、明らかに自分が送金したことになります。実際、サーバー・ログには、送金したのはまさにあなたであることが記録されています。


悪用のシナリオ

Altoro Mutual という架空の銀行では、あるページで特定の口座番号への送金を処理しています。以下に、送金リクエストの一例を示します。

http://www.altoromutual.com/bank/transfer.aspx?creditAccount=1001160141&transferAmount=1000

あるアタッカーがこのリンクを見て、誰か他の人にこのリンクにアクセスさせれば、彼の海外の口座にいくらでも金額を送金できることに気付いたとします。

アタッカーは、以下のように e-メールでそのリンクを送信します。

Dear customer of Altoro Mutual,

We recently applied several security improvements to our server that require you to revalidate your account.

Please click the following link to proceed.

けれども、e-メールを送信したとすると、アタッカーのもくろみがばれてしまいます。それは、ユーザーに「Successfully transferred $1000 to account 1001160141 (口座番号 1001160141 に 1000 ドルを送金しました)」というメッセージが表示される場合は、なおのことです。

一方、ユーザーが何の気なしに、アタッカーが仕込んだリンクにアクセスしてしまうように仕向けることができたらどうでしょう?

アタッカーにとって都合の良いことに、Altoro Mutual の多くのユーザーは金融関係のディスカッション・フォーラムの常連です。この Altoro Communityという架空のサイトでは、フォーラムの投稿に組み込まれるアバターを作成することができます。

フォーラムのアバターは、以下のような一般的な人の姿のイメージです。

図 1. AltorJ Community サイトのアバターのサンプル画像
単純な AltorJ Community サイトのアバター画像

アバターは、例えば以下のようにユーザーの投稿に組み込まれます。

表 1. フォーラムの投稿に組み込まれた AltorJ Community アバターの例
アバターの例投稿の例
フォーラム投稿に組み込まれた AltorJ Community のアバター画像
悪質なハッカー
50 件の投稿
こんにちは

Altoro の最新の決算報告書をもう見ましたか?

このコミュニティー・サイトでは、ユーザーがカスタム・アバターへの URL を指定できるようになっています。通常、カスタム・アバターを指定するには、以下のようなフィールドに入力します。

表 2. カスタム・アバターの指定
フィールドの例URL の例
アバターを指定:http://some_image_site_found_with_google/random_image.jpg

アタッカーが転送リンクをアバターとして使ったとしたらどうなるでしょう?以下は、その一例です。

表 3. アタッカーが指定するアバター
フィールドの例URL の例
アバターを指定:http://www.altoromutual.com/bank/transfer.aspx?creditAccount=1001160141&transferAmount=1000

この場合、ユーザーがコミュニティー・フォーラムを訪れてアタッカーが作成した投稿にアクセスすると、ブラウザーがアバターをロードしようとする際に、必ずリクエストが実行されることになります。アタッカーのアバターの画像はロードされません。ユーザーが Altoro オンライン・バンキングにブラウザーの別のタブでログインしているとしても、アタッカーのフォーラム・トピックにアクセスするすべてのユーザーが、アタッカーに送金することになります。

図 2. アタッカーがアバター画像を使わずに投稿する例
アバター画像が表示されないアタッカーの投稿を示す画像

そのような危険があっても、フォームを使用して送金すれば被害を受けないはずだと考えていませんか?

その考えは当たっています。ほとんどの送金リクエストは、フォーム・リクエストを送信することによって開始されます。そのようなリクエストは、アバターの例のようにアタッカーが簡単に悪用することはできません。ただし、アタッカーにはフォーム・リクエストに対処する手段がいくつかあります。その 1 つは、アタッカーが送金リクエストを送信するフォームのあるページを作成して、そのリクエストを悪質な Web サイトから送信するというものです。

アタッカーは、ページをアバターとして使用することはできませんが、ある種の金融関係のブログのように見せ掛けて、犠牲者をそのページにアクセスさせることはできます。

リスト 1 に、悪質なサイトでのページを記載します。

リスト 1. 悪質な Web ページのサンプル・コード
<html>
<body onLoad="document.getElementById('transferForm').submit()">

<form id="transferForm" action="http://www.altoromutual.com/bank/transfer.aspx" method="post">

<input type="hidden" name="creditAccount" value="1001160141">
<input type="hidden" name="transferAmount" value="10">

</form>

</body>

このフォームは、URL がロードされると自動的に送信されることに注目してください。フォームを送信するのに、ユーザーの操作は一切必要ありません。


XSRF から保護する

銀行サイトの開発者がこの攻撃を防ぐには、どのような方法があるでしょうか?ここからは、XSRF 攻撃に対処する方法をいくつか紹介します。

リファラーによるソリューション

最も単純な方法は、ブラウザーのリファラー・ヘッダーを利用するというものです。ほとんどのブラウザーは、Web サーバーに対し、リクエストがどのページから送信されているのかを通知します。リスト 2 に、ブラウザーからサーバーに送信された悪質なサイトのリクエストの例を記載します。

リスト 2. サーバーに送信された悪質なリクエストの例
POST /bank/transfer.aspx HTTP/1.1
Referer: http://evilsite.com/myevilblog
User-Agent: Mozilla/4....
Host: www.altoromutual.com
Content-Length: 42
Cookie: SessionId=x3q2v0qpjc0n1c55mf35fxid;

creditAccount=1001160141&transferAmount=10

開発者は、リファラー・ヘッダーを銀行のホストのドメイン名と比較して、該当しないリクエストはすべて拒否するように作成することができます。以下に、一例を記載します。

If(request.getHeaders("referer") != null 	&&request.getHeaders("referer").indexOf(
	"http://www.altoromutual.com") != 0){
	throw new Exception("Invalid referer");
        }

さらに、例えば信頼できるサイトにリクエストを実行させなければならない場合など、必要に応じて許可する URL のリストを指定することもできます。

この方法を基本のサーブレットまたはページ・クラスに適用すれば、同じ保護対策をサイトのすべてのページに継承させることができます。ただし、他のサイトに Altoro にリンクすることを許可しなければならない場合、この方法によってリンクが切れてしまうことに注意してください。例えば、Altoro の顧客が Google から Altoro のサイトにアクセスできなくなります。

GET /marketingannouncements HTTP/1.1
Referer: http://www.google.com

それよりも賢明なソリューションは、認証が必要なページだけを保護することです。

リファラーによるソリューションは、e-メールで送信されたサイトへのリンクに対する保護手段にはなりません。また、このソリューションはクライアントを利用して、リファラー値を適切に設定および処理します。プライバシー関連のソフトウェアがヘッダーを削除する可能性があるとしたら、この保護手段は信頼できないものになってしまいます。

リファラーによるソリューションの長所は、他の HTTP ベースのやりとり (Web サービスなど) の以前のバージョンにも対応することです。例えば、クライアント・モバイル・アプリケーションがサイトの REST API を利用している場合、そのクライアントはリファラー・ヘッダーを使用しないため、クライアントにとってリファラー・ソリューションは透過的です。

ただし、以前のバージョンへの対応があまり重要でない場合は、さらに強力なソリューションがあります。その 1 つが、トークンを使用して、機密性の高いリクエストを期限切れにするというソリューションです。

トークンによるソリューション

トークンによるソリューションは、ユーザーがログアウトした時点、またはタイムアウト期間が経過すると失効するパラメーターをフォームに追加するという方法を利用します。リスト 3 を見てください。

リスト 3. トークンによるソリューションの例
<form id="transferForm" action="https://www.altoromutual.com/bank/transfer.aspx" method="post">

Enter the credit account:
<input type="text" name="creditAccount" value="">
Enter the transfer amount:
<input type="text" name="transferAmount" value="">

<input type="hidden" name="xsrftoken" value="JKBS38633jjhg0987PPll">

<input type="submit" value="Submit">

</form>

トークンをクエリー・パラメーターとして使用することはできません。それは、トークンをクエリー・パラメーターとして使用すると、セッション情報が、ブラウザーの履歴や Web ログ・メトリクスおよびアナリティクスで可視になってしまうためです。例えば、以下のリクエストは賢明な考えではありません。

リスティングを見るにはここをクリック

すべてを網羅する手段であらゆるタイプのリクエストを保護し、トークン値が URL で公開されないようにする最善の手法は、HTTP ヘッダーを使用することです。一例として、リスト 4 を参照してください。

リスト 4. HTTP XSRF トークン・ヘッダーの例
POST /bank/transfer.aspx HTTP/1.1
Referer: https://www.altoromutual.com/bank
xsrftoken: JKBS38633jjhg0987PPll 
User-Agent: Mozilla/4....
Host: www.altoromutual.com
Content-Length: 42
Cookie: SessionId=x3q2v0qpjc0n1c55mf35fxid;

creditAccount=1001160141&transferAmount=10

REST API と Ajax をこれまで以上に活用する最近のアプリケーションでは、通常、HTTP ヘッダーのほうが推奨されるソリューションです。ヘッダー・トークンは、例えばリスト 5 のコードを使用して設定することができます。

リスト 5. ヘッダー・トークンの設定
<form id="transferForm" action="https://www.altoromutual.com/bank/transfer.aspx" method="post">

Enter the credit account:
<input type="text" name="creditAccount" value="">
Enter the transfer amount:
<input type="text" name="transferAmount" value="">

<button onClick="addXsrfHeaderAndSubmitForm(dojo.byId(transferForm))" value="Submit">
</form>

フレームワーク全体を保護する

リファラーによるソリューションの場合と同じく、トークンをチェックするのに最適な場所は、すべての認証済みページに影響するようなところです。

優れた設計決定は、そのようなページのすべてを基底クラスから継承させることです。その場合、リスト 6 のようなコードになります。

リスト 6. 基底クラスからの継承
class AuthenticatedServletBase extends ServletBase {

protected bool service(...){
	.....
	if(sessionUtil.getXsrfToken().equals(requestUtil.getXsrfToken())==false){
		showXSRFTokenError();
		return true;// handled..stop any further processing here

	}
	....
}

}

XSRF トークンの有効な副次効果

トークン・ヘッダーによるソリューションは、XSRF 攻撃から保護するだけでなく、保護対象のページに対する他のタイプのクライアント・サイドの攻撃を阻止するというセキュリティー上のメリットがあります。例えば、以下の攻撃を阻止する効果があります。

  • JSON ハイジャック
  • 折り返し型クロスサイト・スクリプティング
  • URL リダイレクトによりフィッシング

XSRF とセキュリティー・スキャン・ツール

セキュリティー・スキャナーが XSRF に対する不備を報告することはよくあります。報告された問題が、実際には脆弱性ではないこともよくあります。その理由は、スキャナーは、リクエストの機密性が高いかどうかかを認知できないためです。けれども、サイトがこの記事で前に説明したすべてを網羅する手段を実装すると、スキャナーはいずれの XSRF 問題も検出しません。

機密性が高いと確信するリクエストだけを修正するのではなく、この記事で説明した方法ですべてのリクエストを修正すれば、経験の浅い開発者が潜在的な問題を取り込むことがなくなるかもしれません。

参考文献

学ぶために

製品や技術を入手するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=セキュリティ, Web development
ArticleID=974445
ArticleTitle=クロスサイト・リクエスト・フォージェリーを防ぐ: ブラウザーのタブに潜む危険を認識する
publish-date=06262014