2007年6月7日 はてなブックマークのコメントをうけて、「常にJSONP、JSON、JavaScriptに機密事項を含めないように」という主張を改め、「クロスドメインアクセスの対策をとっていない状態ではJSONP、JSON、JavaScriptに機密事項を含めないように」という主張に関して記述しました。
こんにちは、SEの進地です。
今回から週単位でWebアプリケーションのセキュリティに関するエントリーを書いていこうと思います。
僕自身、日々勉強して精進というところですので、もし何らかの誤りがあれば是非ご指摘ください。
つっこみ大歓迎です。
今回取り上げるのはWeb 2.0なアプリケーションでセキュリティ面で気をつけるべきことの一つ、機密情報にJSONPでアクセスするなです。
JSON(JavaScript Object Notation)はJavaScript(ECMAScript)のサブセットをベースに設計されたテキストによるデータフォーマットの一種で、JavaScriptから容易に取り扱うことができ、また、シンプルな構造をテキストに表現することから人間による可読性も高いという特徴があります。また、JSONには自ドメインのWebページからのアクセスしか許可されない「クロスドメインの制約」があります追記:また、JSONの取得は多くの場合XMLHttpRequestによって行われ、また、XMLHttpRequestには自ドメインのWebページからのアクセスしか許可されない「クロスドメインの制約」があります。(※3)
JSONP(JSON with Padding)を使うことでこの制限を越えてドメインを超えたJSONを利用したデータのやりとりが行えるようになります。追記:「クロスドメインの制約」はJSONの制約ではなく、XMLHttpRequestの制約です。その為、JSONでもXMLHttpRequestを使用せず、<script>タグのsrc属性で直接読みこむことが可能です。そのため、JSONPにとどまらず、JSON、およびJavaScriptには機密情報は一切書き込んではいけません。さらに追記:そのため、クロスドメインアクセスの対策がとられていない状態ではJSONP、JSON、JavaScriptに機密情報を含めてはいけません。つっこみありがとうございますm(_ _)m>kazuhookuさん
そのため、JSON、JSONPはAjax(Asynchronous JavaScript and XML)を利用したWeb2.0なマッシュアップサービスで広く使われています。
今回、JSONPを用いて機密情報にアクセスすることでCSRF(Cross Site Request Forgeries)脆弱性が生じることを示します。CSRFとはサイトをまたがってユーザの意図しない機能が勝手に実行されてしまう脆弱性です。
例えば、あるログインが必要なサイトがあり、そのサイトではログインした状態でユーザの機密情報(例えば、友達のメールアドレスのリスト)などをJSONPで取得できるサービスがあるとします。このサイト、サービスをそれぞれサイトA、サービスAとします。
GMail Vulnerable To Contact List Hijacking
http://cyber-knowledge.net/blog/2007/01/01/gmail-vulnerable-to-contact-list-hijacking/
GMail's Flaw Is Now Fixed
http://cyber-knowledge.net/blog/2007/01/02/gmails-flaw-is-now-fixed/
一見、ログインしたユーザーに機密情報を開示するのだから問題ないのでは?と考えるかもしれませんが、それは誤っています。次のシナリオを考えてみましょう。
先にも書いたようにJSONPはJSONXMLHttpRequestの「クロスドメインの制約」を取り払います。その為、JSONPでアクセスされる情報は常に任意の悪意あるサイト(ドメイン)からアクセスされる可能性があることに注意が必要になります。ログイン認証はCSRF脆弱性に対してなんら対策にはなりえないことにも注意が必要です。先のシナリオでは被害者がログイン済みであれば何の障害も無く攻撃者は機密情報を取得できるのです。下図は悪意のサイト(図内で赤色の菱形で表示。緑色の四角は善意のサイト。)がJSONXMLHttpRequestによるデータ取得ならサイトAの機密情報にはアクセスできなかったが、JSONP、またはXMLHttpRequestによらないデータ取得ではアクセスできてしまうことを表現しています。
ログインを要求するサイトでは、ユーザの利便性を重視して、Cookieを利用してセッション情報をブラウザがキープし続けるものも多々あります。GMailやmixiといったサービスサイトでも、自動ログイン機能が用意されていたりします。こうした自動ログイン機能を利用している間、ユーザーは常にログイン済みになっていることに注意が必要です(※1)。先のシナリオで、サイトAがこうした自動ログイン機能を持つサイトであれば、被害者は既にログイン済み(であることが多い)ですから、攻撃者は単に自サイトにスクリプトBを仕掛けておくだけで多くの攻撃を成功させることができます。自動ログイン機能を持たない場合でも、攻撃者はページ上にサイトAへのリンクを記述しておき、ログインを誘導することができます(例えばGMailのアドレスにmailto:でリンクを張るなど)。
従って、ログイン済みユーザーに向けたサービスであるなしに関わらず、決してJSONPで機密情報にアクセスできるようにしてはいけないのです。JSONPに機密情報が含まれているということは、ユーザーはどこに潜んでいるかわからない攻撃者に対して常に機密情報を首から堂々とぶら下げて歩いているようなものなのです。追記:クロスドメインアクセスの対策をとっていない状態ではJSONPで機密情報にアクセスできるようにしてはいけません(※2)。
JSONPを用いたサービスの構築をする際は、公開情報に重々注意しましょう。
追記:JSONPだけではなく、JSON、またJavaScriptファイルにも機密情報は決して含めないように注意しましょう。さらに追記:クロスドメインアクセスの対策をとっていない状態でJSONP、JSON、JavaScriptに機密情報を含めないように注意しましょう。つっこみありがとうございますm(_ _)m>kazuhookuさん
注釈:
※1 ワンタイムトークン等を利用して、CSRF対策がとられている場合は別です。
※2 もっとも、これはJSONPに関わらず、CSRF脆弱性への対策がとられていないサイト、サービス一般にも言えることです。ログイン済で利用できるサービスに機密情報が含まれており、かつ、そのサイト、サービスにCSRF脆弱性への対策がとられていなければその機密情報は漏えいの危険に常にさらされています。追記:JSON/JSONPによらないCSRFでは攻撃者はサーバのレスポンスを取得できないのでCSRF脆弱性への対策がとられていないことで機密情報が漏えいの危険に常にさらされているというのは誤りでした。つっこみありがとうございますm(_ _)m>HiromitsuTakagiさん
※3 「クロスドメインの制約」はJSONの制約ではなく、XMLHttpRequestの制約でした。つっこみありがとうございますm(_ _)m>志田さん。 本文中にも追記しましたが、JSONの取得には多くの場合XMLHttpRequestが利用されるため、この場合は「クロスドメインの制約」が発生しますが、<script>のsrc属性を利用して直接JSONを読み込むことでこの制約は易々と突破できますので、充分注意が必要です。