先日も
twitter上の犯行予告により20歳の青年が逮捕されたようですが、なりすましによる誤認逮捕ではなかったのか気になるところです。そこで、twitterが、なりすまし投稿をどの程度対策しているかを調べてみることにしました。twitterの安全性を確認することが目的というよりも、twitterが実施している対策を知ることにより、皆様のWebサイトを安全にする参考にしていただければと思います。
今回調べた「なりすまし投稿」の手法は下記の通りです。
- クロスサイト・リクエスト・フォージェリ(CSRF)
- クロスサイトスクリプティング(XSS)
- HTTPヘッダーインジェクション
- クリックジャッキング
- DNSリバインディング
- クッキーモンスターバグ
このうち、上の5つの解説は拙稿「
“誤認逮捕”を防ぐWebセキュリティ強化術」、最後のクッキーモンスターバグについては、過去のエントリ「
クッキーモンスターバグがあると、IPアドレス偽装防止のCSRF対策が回避される」をご覧下さい。
それでは、はじめます。
CSRF
CSRF対策として、twitterは標準的なトークンによる対策を採用しています。以下は、書き込み時にPOSTされるデータの例です。大文字のXは伏せ字です。
authenticity_token=ee09XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX63faec&place_id=&status=【投稿内容】
authenticity_tokenがトークンですね。ワンタイムではない、セッション限りのトークンを使っているようですが、これで問題ありません。
試みに、authenticity_tokenを一文字だけ改変してツイートしてみると、以下のようにエラーになります(Ajax/JSONのリクエストなので、エラー表示は呼び出し側でします)。
HTTP/1.1 403 Forbidden
【以下略】
ということで、CSRFについては対策されています。
XSS
twitterはXSSの悪用事例が2009年(JS.Twettir)と2010年にあるので、XSS攻撃を完璧に防御しきっているわけではありませんが、世界中の著名なセキュリティ研究者やバグハンターがtwitterの脆弱性を調べ、twitter側もそれを改修していので、現在では、未知のXSSを見つけるのは難しいと思います。
twitter社は年度毎に脆弱性報告の貢献者を表彰しており、
このページから見ることができます。日本人も、
小菅さん、
kinugawaさん、
malaさん、
はせがわようすけさんなど、日本の錚々たるバグハンターが名を連ねているので、彼らが見つけていないXSS脆弱性を探して犯行予告なりすましに使うのは相当困難ではないか思います。
HTTPヘッダーインジェクション
HTTPヘッダーインジェクションについてはきちんと調べていないのですが、HTTPヘッダーインジェクション脆弱性が入る局面は、HTTPレスポンスヘッダ(Set-Cookie、Locationその他)の出力内容に外部からコントロールできる値を含む場合であり、twitterのレスポンスには、そのような箇所が見あたりません。おそらく大丈夫だろうということと、仮にHTTPヘッダーインジェクション脆弱性がtwitterにあれば、先のバグハンター達が見つけてくれるでしょう(他力本願)。
クリックジャッキング
先のエントリ「
IPAから「クリックジャッキング」に関するレポート出ました」にて、X-FRAME-OPTIONSヘッダを出力している数少ないサイトの1つがtwitterであることを説明しました。このため、利用者がモダンなブラウザを使う限り、クリックジャッキングには対策済みということになります。
問題は、利用者がIE6やIE7を使っている場合です。これらはまだメンテナンスされているブラウザですが、X-FRAME-OPTIONSには対応していません。そこで、twitterがIE6/IE7に対して、クリックジャッキング対策をどのようにしているのか、あるいはしていないのかを調べてみました。
まず前提として、現在IE6/IE7でtwitterを利用しようとすると、mobile.twitter.comにリダイレクトされます。
このため、IE6/IE7ユーザ向けの罠としては、
mobile.twitter.com用の罠に変更する必要があります。これをIE7で閲覧すると下記の状態になります。
後は、これをクリックジャッキング用の罠のiframeに入れてやる訳です。IE7はX-FRAME-OPTIONSに対応していないので大丈夫だろうと試してみると…以下のようになります。
twitterにログインした状態なのに、iframeの中はログイン画面になっていますね。これは、twitterが
P3Pコンパクトポリシーを出力していないので、iframeの中のページはCookie(第三者Cookie)の送信がブロックされているためです。ブラウザのステータスバー中央に目のアイコンに停止マークがついていますが、ここをダブルクリックして詳細を確認しましょう。
たしかに、P3Pコンパクトポリシーが送信されていないために、罠サイトからは第三者CookieとなるtwitterのCookieがブロックされています。大丈夫のようですね…
でも、絶対に大丈夫でしょうか。IEの設定を変更している場合は、P3Pコンパクトポリシーがなくても第三者Cookieを送信する可能性があります。
その設定は、インターネットオプションのプライバシータブで変更可能です。まず、IEのデフォルトを確認しましょう。
デフォルトではCookieの設定は「中」で、「コンパクトなプライバシーポリシー(注:P3Pコンパクトポリシーのこと)のないサードパーティのCookieをブロックします」とあります。これが効いている訳ですね。
ここで、好ましくはありませんが実験のため、プライバシーの設定を最低レベルにしてみましょう(試す場合は、試験環境で実行するか、元に戻すのを忘れずに)。
これで、Cookieの制約はなくなりましたので、先ほどの罠をもう一度閲覧してみましょう。
あれあれ、アドレスバーに注目ください。iframeに入れたはずなのに、iframeを飛び出してしまいました。これでは、騙される人はいなさそうです。どうもJavaScriptによる対策が入っているようですね。調べてみると、以下のコードがあります。
if (window.top !== window.self) {document.write = "";window.top.location = window.self.location; // 以下略
これは、IPAの『
「クリックジャッキング」に関するレポート』にも紹介されているコードで、iframeなどに入れられていないかチェックして、入れられている場合は、自身をトップレベルに表示させるようにするものです。但し、この種の手法の回避策も研究されているため、これだけで完全な対応というわけではありません。だからこそ、X-FRAME-OPTIONSという機能追加が必要であったわけですが、詳しくはIPAの『
「クリックジャッキング」に関するレポート』を参照下さい。
ここでは、元々利用者がJavaScriptを無効にしていたというシナリオで、罠のサイトを閲覧してみます。
ようやく、twitterの画面をiframeに入れることができました。あとは、今は見ているtwitterの表示を「透明にして」、その下に、利用者が思わずクリックしたくなる罠の表示を入れるだけです。
ここまでを振り返って、IEで、twitterの画面をiframeに入れるために何をしなければならなかったを振り返って見ると、以下の通りです。
- 古いバージョンのIE(IE7以前)を使う
- プライバシーの設定を最低(すべてのCookieを受け入れ、送信)
- JavaScriptを無効にする
これは率直に言って、利用者側の自業自得感が相当ありますね。
立場を変えて、twitterがどのような対策をしたかを以下にまとめます。
- HTTPレスポンスヘッダ x-frame-options: SAMEORIGIN を送信
- P3Pコンパクトポリシーを送信しない
- JavaScriptによるクリックジャッキング対策コード
現時点の最高レベルの「なりすまし犯行予告対策」をしたいWebサイトは、上記を参考にすると良いでしょう。
DNSリバインディング
一般的にDNSリバインディング攻撃でも「なりすまし犯行予告」は可能ですが、DNSリバインディングでは利用者のセッションをハイジャックすることはできません。その理由は、DNSリバインディング攻撃の場合、利用者な罠のドメイン名で攻撃対象サイトをアクセスするため、利用者のセッションは有効にならないためです。
それでは、なりすましできないじゃないかと思ってしまいますが、なりすまし犯行予告で重要な「なりすまし」要素はリモートIPアドレスであって、利用者のアカウントではありません。この前提であれば、DNSリバインディング攻撃が使えます。その手順は以下の通りです。
- 攻撃者は自分の用意したアカウントでログインしてCookieを調べる
- 攻撃者はDNSリバインディングの罠を用意する。罠を閲覧した利用者のブラウザに対して、前項で調べたCookieをセットする
- 利用者からの閲覧があった直後に、罠のドメイン名に対するAレコードを書き換え、攻撃対象のIPアドレスをセットする。TTLは元々短い値(1秒など)とする
- 利用者が閲覧した罠から、時間をおいて(10秒~数分)罠のドメイン名にXMLHttpRequestでアクセスする。罠のドメイン名は攻撃対象サイトのIPを指しているので、実際には攻撃対象にアクセスする
- 利用者のブラウザは、攻撃者の用意したアカウントで攻撃対象サイトにログインした状態になる
- XMLHttpRequestでCSRF対策のトークンを調べ、正しいトークンをセットして「なりすまし投稿」を行う(twitterの場合であれば、セッション毎に固定のトークンなので、攻撃者があらかじめてトークンを調べて罠にセットしてもよい)
この、DNSリバインディング + セッションフィクセイションのような攻撃については、過去に「
誤報訂正:『2010年に最も警戒すべきセキュリティ脅威は「DNSリバインディング」』報道について」で取り上げています。当時は、『なんとなくトホホ感の漂う攻撃手順だ。ホンマカイナ。』と批評した手順ですが、思わぬところで利用価値(?)が出てきました。
さて、DNSリバインディングへの対策ですが、前述の通り攻撃対象サイトには「罠のドメイン名」がHostヘッダに入ります。XMLHttpRequestではHostヘッダは変更できないため、HostヘッダのチェックでDNSリバインディング対策できます。
それでは、twitterはどうでしょうか。自分の持つドメイン名に twitter.comのIPアドレスをセットしてアクセスしてみると下記の応答になります。
HTTP/1.0 404 Not Found
date: Sun, 31 Mar 2013 15:34:54 UTC
server: tfe
strict-transport-security: max-age=631138519
Content-Length: 0
ちゃんと対応していますね。随分素っ気ないレスポンスですが、攻撃者に対してこれでよいのでしょう。
簡単にDNSリバインディング対策する方法として、Apacheのバーチャルホスト機能を使う方法があります。
NameVirtualHost *:80
# ダミーのバーチャルホスト
<VirtualHost _default_:80>
DocumentRoot /var/www/dummy
ErrorDocument 404 /index.html
</VirtualHost>
# 本番のバーチャルホスト
<VirtualHost>
ServerName www.example.jp
# 以下略
VirualHostで _default_ を指定することで、「その他の」Host指定に対するリクエストをここに集めることができます。通常はエラー表示を出すようにしておけばいいでしょう。
クッキーモンスターバグ
以前のエントリ「
クッキーモンスターバグがあると、IPアドレス偽装防止のCSRF対策が回避される」にて、地域型JPドメイン名や都道府県型JPドメイン名(などクッキーモンスターバグのおこるドメイン名)を使うと、トークンによるCSRF対策が回避されると説明しました。認証のあるサイトでも、前項と同じように攻撃者のアカウントでログインさせて、利用者(被害者)のリモートIPアドレスで「犯行予告」を書き込みできる場合があります。詳しくは、先のエントリをご覧ください。
では、twitterはどうかというと、.comドメイン名なので、クッキーモンスターバグの影響はない、すなわち大丈夫です。
まとめ
twitterを題材として、「なりすまし投稿対策」がどのように実施されているかどうかを調べました。
まとめると以下の通りです。
- トークンによるCSRF対策
- XSS対策(脆弱性報告者の表彰)
- HTTPヘッダーインジェクション対策(あるいは該当箇所なし)
- クリックジャッキング対策(下記)
- X-FRAME-OPTIONSヘッダの送信
- P3Pコンパクトポリシーを送信しない
- JavaScriptによるクリックジャッキング対策
- Hostヘッダのチェック
- クッキーモンスターバグの影響を受けないドメイン名の採用
なりすまし投稿が重大な影響を及ぼす場合、twitterの取り組みが参考になるでしょう。
一方、以下のような場合はtwitterによるなりすまし投稿があり得ます。こちらは利用者が気をつけるしかなさそうです。
- 利用者がフィッシング詐欺に引っかかってIDとパスワードを盗まれた場合
- 悪質なtwitterアプリの連携を利用者が許可してしまった場合
- 使用しているtwitterアプリに脆弱性があり、悪用された場合