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

第3回 Webセキュリティのおさらい その3 CSRF・オープンリダイレクト・クリックジャッキング

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

前回は,Webアプリケーションにおける受動的攻撃の代表例の1つであるXSSについて,原理や対策を振り返りました。今回は,同じく受動的攻撃の代表例であるCSRF,オープンリダイレクト,クリックジャッキングについて掘り下げて解説していきます。

CSRF(クロスサイトリクエストフォージェリ)

CSRFはどのように引き起こされるのか

CSRFとは,たとえば掲示板の書き込みや設定情報の変更などの機能に対して,攻撃者のサイト上に設置されたフォームなどから強制的にリクエストを発行することで,ユーザーの意図していない操作と同様の結果をもたらす攻撃手法です。Webアプリケーションに永続的な副作用がある機能が攻撃の対象となります。

たとえば,http://example.jp/上に設置された掲示板で以下のようなHTMLがあったとします。

<form method="POST" action="/board">
    <label for="username">お名前</label>
    <input type="text" id="username" name="username">
    <label for="message">メッセージ</label>
    <textarea id="message" name="message"></textarea>
    <input type="submit" value="書き込み">
</form>

このフォームを用いて,「お名前」欄に「田中」,「メッセージ」欄に「こんにちは。」を入力した状態で「書き込み」ボタンを押し,掲示板へテキストを書き込むときのブラウザからWebサーバへのHTTPリクエストは以下のようなものになります。

POST /board HTTP/1.1
Host: example.jp
Content-Type: application/x-www-form-urlencoded

username=田中&message=こんにちは。

本来は,これら以外にも多くのHTTPリクエストヘッダが付与されますが,ここでは説明をかんたんにするために,必要最小限のヘッダのみを示しています。また,リクエストボディ中のusernameおよびmessageパラメータは,本来はURLエンコードされ`username=%E7%94%
B0%E4%B8%AD&message=%E3%81%93%E3%82%93%E3%81
%AB%E3%81%A1%E3%81%AF%E3%80%82`のようになりますが,これも説明をかんたんにするために,そのまま日本語のテキストで書き示しています。

サーバ側は,このようなリクエストを受け取ると,usernameおよびmessageのパラメータをそれぞれ掲示板の内容として内部のデータベースに書き込みます。

このような掲示板に対して,攻撃者が自身の罠サイトであるhttp://attacker.example.com/trap.html上に,以下のようなHTMLを用意したとします。

<body onload="document.forms[0].submit()">
       <form method="POST" action="http://example.jp/board">
       <input type="text" name="username" value="名無しさん">
       <textarea name="message">これは犯罪の予告です。XX月XX日,YYYにて大規模な犯罪を行います。</textarea>
   </form>
</body>

フォーム自体は攻撃者のサイトであるhttp://attacker.example.com上にありますが,フォームの送信先が掲示板の設置されているhttp://example.jp/boardになっています。

攻撃者は,このような罠ページを用意したのち,SNSやメール,ほかの掲示板などを経由してhttp://attacker.example.com/trap.htmlというURLを第三者に伝え,だれかがこのURLを訪問するのを待ちかまえます。

ユーザーがうっかりこのURLをクリックして攻撃者の用意した罠サイトを訪問すると,ページを開いた瞬間にJavaScriptが動作し,以下のようなHTTPリクエストがユーザーのブラウザから掲示板の設置されているhttp://example.jpに対して発行され,攻撃者の用意した内容のメッセージ,すなわち犯罪予告がexample.jp上の掲示板に書き込まれてしまいます。

POST http://example.jp/board HTTP/1.1
Host: example.jp
Content-Type: application/x-www-form-urlencoded

username=名無しさん&message=これは犯罪の予告です。XX月XX日,YYYにて大規模な犯罪を行います。

掲示板への書き込みのリクエストは,攻撃者ではなく,罠ページを閲覧したユーザーのブラウザから行われますので,掲示板上で書き込みのIPアドレスを記録している場合にはユーザーのIPアドレスが記録されます。そのため,掲示板への犯罪予告の書き込みに対して警察などによる捜査が行われた場合には,攻撃者ではなく,罠ページを閲覧したユーザーが捜査対象となってしまうこともありえます。

このように,Webアプリケーションにおいて副作用の発生するリクエストを,罠ページなどを経由してユーザー自身に発生させる攻撃手法がCSRFです。

ログインを利用してメールアドレスを強制的に変更してしまう仕組み

では次に,CSRFの対象となるWebアプリケーションが掲示板ではなくログイン機構を持つものであった場合を考えてみましょう。

たとえば,ログイン後の個人設定の変更においてメールアドレスを変更するためのフォームがあったとします。

<form method="POST" action="/changeaddr">
    <label for="email">メールアドレス</label>
    <input type="email" id="email" name="email" value="yourmail@example.jp">
    <input type="submit" value="メールアドレスを変更する">
</form>

このフォームを用いて,メールアドレスとしてnewaddr@example.jpを設定した場合のブラウザからWebサーバへのHTTPリクエストは以下のようなものになります。

POST /changeaddr HTTP/1.1
Host: example.jp
Cookie: sessionid=25283FB24C9DEE32
Content-Type: application/x-www-form-urlencoded

email=newaddr@example.jp

すでにWebアプリケーションにはログイン済みであるため,ログイン後のセッションIDであるCookieがリクエスト内のCookieリクエストヘッダとして送信されています。

サーバ側は,このようなリクエストを受け取ると,データベース内に登録されているユーザーのメールアドレスをnewaddr@example.jpに変更して書き込みます。

このような設定画面を持つWebアプリケーションに対して,攻撃者は自身の罠サイトであるhttp://attacker.example.com/trap.html上に今度は以下のようなHTMLを用意します。

<body onload="document.forms[ 0 ].submit()">
   <form method="POST" action="http://example.jp/changeaddr">
       <input type="email" name="email" value="hijack@attacker.example.com">
   </form>
</body>

攻撃者はこのような罠ページを用意したのち,先ほどの掲示板のときと同様に,http://attacker.example.com/trap.htmlというURLをSNSやメール,ほかの掲示板などを経由してほかのユーザーに伝え,そのユーザーが罠URLを訪れるのを待ちかまえます。

すでにログイン済みのユーザーがこのURLを訪問すると,以下のようなHTTPリクエストがユーザー自身のブラウザからWebアプリケーションの設定画面に対して発行されます。

POST http://example.jp/changeaddr HTTP/1.1
Host: example.jp
Cookie: sessionid=25283FB24C9DEE32
Content-Type: application/x-www-form-urlencoded

email=hijack@attacker.example.com

ユーザー自身はWebアプリケーションにすでにログイン済みですので,Webアプリケーションに対してのリクエストにはセッションIDを含むCookieがそのまま付与されます。結果として,ユーザー自身は意図していないにも関わらず,メールアドレスが攻撃者のものに強制的に変更されてしまうことになります。

このように,攻撃者の用意した罠ページを起点とし,ユーザー自身に攻撃対象となるサイトへのリクエストを発行させることによって,ユーザー自身が意図していない処理を行わせるのがCSRFです。

CSRFへの対策

CSRFへの対策としては,攻撃者が知りえない値をリクエスト内に埋め込む,すなわち

  • フォーム内にhiddenを用いてトークンを埋め込む
  • サーバ側でリクエストを受け取ったときに,そのトークンを確認する

という方法がもっとも広く使われています。たとえば以下の例では,tokenという名前でhiddenが指定されたinputタグに,攻撃者には推測できないランダム値を埋め込んでいます。

<form method="POST" action="/changeaddr">
    <label for="email">メールアドレス</label>
    <input type="email" id="email" name="email" value="yourmail@example.jp">
    <input type="hidden" name="token" value="C2A8DDEF926432BD">
    <input type="submit" value="メールアドレスを変更する">
</form>
<form>

サーバ側では,formのPOSTリクエストを受け取ったときに,tokenの値が正しいものか検証することで,リクエストが正規の画面遷移によって発行されたものであることを確認できます。

トークンを利用する方法以外にも,パスワードを再入力させる方法や,CAPTCHAなどを利用する方法もありますが,本稿では説明は省略します。

著者プロフィール

はせがわようすけ

株式会社セキュアスカイ・テクノロジー常勤技術顧問。 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/

バックナンバー

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

コメント

コメントの記入