鳩丸よもやま話

bakera.jp > 鳩丸よもやま話 > サンシャイン牧場 情報「露出」問題のまとめ

サンシャイン牧場 情報「露出」問題のまとめ

「サンシャイン牧場」において、課金操作を行った人のメールアドレスと電話番号が「露出」していた件のまとめです。

はじめに

「サンシャイン牧場」はmixiアプリとして提供されているゲームです。mixiアプリとしては最大の利用者数を誇り、2009年11月23日現在、利用者は300万人を突破しています。運営しているのはRekooという中国の会社です (が、最近、日本法人もできました)。

2009年10月21日、サンシャイン牧場に「Kコイン」の仕組みが導入されました。実際のお金を支払って「Kチャージ」を行うとKコインが増え、Kコインを消費することで、通常では購入できない作物や肥料などを手に入れられる仕組みです。リアルのお金を支払ってアイテムを購入するという、いわゆるアイテム課金の制度になります。支払い方法は、株式会社ゼロの決済代行サービスを利用したクレジットカード払いでした。

ところが、この課金に際してRekoo側が用意したシステムには、技術的な問題点がいくつかありました。

私は10月22日の深夜に問題を確認し、「情報セキュリティ早期警戒パートナーシップ」の制度を利用して、2つの問題を報告しました。その結果、翌23日の昼頃に「Kチャージ」の機能が一時停止。夜になってKチャージの機能が再開されましたが、その際には私が報告した問題は修正されていました。

「情報セキュリティ早期警戒パートナーシップ」にはガイドラインが存在し、取扱中は「脆弱性関連情報」を公開してはならないことになっています。修正が行われた後も取扱中の状態が続いていましたが、11月18日になって取扱終了の連絡を受けましたので、ここで改めて問題の内容についてまとめてみようと思います。

なお、私が持っている情報は限られています。私は外部からシステムを見たに過ぎず、システムの正確な仕様やソースコード、データベースの内容、アクセスログなどを閲覧できる立場にはありません。その立場は一般利用者と同じものです。推測で述べている部分も多くなっていますので、その点はあらかじめご承知ください。

問題発覚の経緯

「サンシャイン牧場」課金の流れ

まず、通常の課金の流れを確認したいと思います。当時、Kコインチャージの操作手順は以下のようになっていました。

  • 「サンシャイン牧場」に入る。
  • 画面上部の「Kチャージ」、もしくは画面左上のKコイン所持数表示部分をクリック。
  • チャージの種類を選択する画面になるので、チャージするコインの数と金額を選択。
  • 「前回のクレジットカードを使う」「新たなクレジットカードを使う」のいずれかをクリック。

すると、以下のようなメッセージが表示されます。


外部サイトへの遷移
「サンシャイン牧場」 は、外部サイトへ遷移しようとしています。
外部サイトを訪れる場合は、以下のURL をクリックしてください。
http://mxfarm.rekoo.com/zerotransfer/?uid=182754&money=1000&cf=old
(※リンク先は、mixiのコンテンツやサービスではありません。)

これはmixi側が出している警告で、mixiアプリから外部サイトに移動する際に出るもののようです。

課金時にはいったんmixiの外に出て、Rekoo社のサイトである http://mxfarm.rekoo.com/…… にアクセスすることになります。以降、これを「課金用URL」と呼ぶことにします。

課金用URLにアクセスすると、入力フォームが現れます。このとき、ブラウザのアドレスバーを確認すると、URLは https://credit.zeroweb.ne.jp/cgi-bin/order.cgi?orders となっていて、ゼロ側のサイトに移動していることが分かります。このフォームで、電話番号、氏名、カード番号、カード有効期限、年齢、メールアドレスを入力することになります。

※なお、現在は上記の課金用URLにアクセスしても何も起きません。

課金用URLについて

課金用URLの「?」以降の部分 (クエリ文字列) には、3つの値が指定されています。これは指定した金額などによって変化します。たとえば、「新たなクレジットカードを使う」で1000円の購入をする際、課金用URLは以下のようになります。

http://mxfarm.rekoo.com/zerotransfer/?uid=182754&money=1000&cf=new

「前回のクレジットカードを使う」で500円の購入を試みると、課金用URLは次のようになります。

http://mxfarm.rekoo.com/zerotransfer/?uid=182754&money=500&cf=old

moneyとcfの値が変化したことが分かります。moneyは購入金額を表し、cfは「新たなクレジットカードを使う」なのか「前回のクレジットカードを使う」なのかを表していると推測できます。

もうひとつ "uid" という値がありますが、名前からユーザーのIDらしいと想像できます。

よく知られていることですが、mixiでは、すべての会員に通し番号をつけて管理しています。ログインした後に「プロフィール確認」を押すと、以下のようなメッセージが表示されます。

他の方から見たばけらさんのトップページです。

(URL は http://mixi.jp/show_friend.pl?id=182754 です。)

プロフィールを変更する場合「プロフィールの変更」よりおこなえます。

この "182754" が私の番号です。mixiのヘルプ等では、この番号は「ユーザーID」と呼ばれています。

ここであらためて課金用URLを見ると、uid=182754は、私のユーザーIDと完全に一致していることが分かります。つまり、uidにはmixiのユーザーIDがそのまま指定されていることになります。

まとめると、課金用URLには3つの値が指定されていて、それぞれの意味は以下のようになります。

  • uid : ユーザーID
  • money : 購入金額
  • cf : 「新たなクレジットカードを使う」か「前回のクレジットカードを使う」か

課金用URLには、セッション鍵のような秘密情報は全く含まれていないように見えます。この時点で、問題がありそうな予感がしてきます。

第1の問題: 第三者に課金操作を行われてしまう可能性

課金用URLにはユーザーIDが含まれていますが、このユーザーIDを別のものに変更したら何が起きるのか、という疑問がわいてきます。他人のユーザーIDを知るのは難しいことでしょうか。

mixiのヘルプを見ると、ユーザーIDを知る方法について、以下のように説明されています。

なお、ユーザーIDは下記方法で知ることができます。

1. 足あとやコメントから該当ユーザーのニックネームを探します。

2. 該当ユーザーが見つかったら、ニックネーム上にカーソルを合わせ、右クリック → プロパティを選択します。

3. プロパティに表示されているURLの末尾数字がIDです。(http://mixi.jp/show_friend.pl?id=○○○○○○)

以上、[mixi] ヘルプ > その他 > 特定のユーザーのアクセスをブロックしたい より

ここでは「足あとやコメントから」となっていますが、コミュニティの書き込みやメンバー一覧にもユーザーのニックネームは表示されており、同じようにしてユーザーIDを知ることができます。

mixiには「サンシャイン牧場」の公式コミュニティが存在しています。当時は課金が始まったばかりで、コミュニティには「Kチャージを利用したけれど……」というような書き込みが多数ありました。書き込んだ人のニックネームも表示されていますから、簡単にユーザーIDを知ることができます。

そうして他人の課金用URLにアクセスしてみると、以下のような挙動を示しました。

  • Kチャージを利用したことのない人のユーザーIDを指定した場合 …… ゼロ側のフォームが表示されました。これは、先に述べたのと同じ挙動です。個人情報が見られたりすることはありませんし、大きな問題はありません。
  • Kチャージを利用したことがある人のユーザーIDを指定した場合 …… 真っ白な画面が現れ、左上に「Success_order」と表示されます。リンクもボタンも何もありません。URLはゼロ側のものになっています。

後者の挙動は完全に予想外です。「○○円になりますがよろしいですか?」という確認も何もなしに、いきなり完了するとは思いませんでした。しかも、結果のメッセージもなんだかおかしなことになっています。

普通、決済代行サービスのサイトに移動して決済を行う場合、決済が完了したら、完了した旨 (あるいは決済に失敗した旨) が分かりやすく表示されるものでしょう。また、何らかの方法で元いたサイトへ戻ることができないと困ります。どう考えても正常とは思えない結果です。

システム内部のエラーが発生して適正なメッセージが表示できなかった、という可能性も考えられます。しかし、メッセージは「Success_order」というものであり、処理が成功したと言っているように読めます。

このことから、以下のように推測しました。

  • ゼロ側のサーバは、課金成功のメッセージを出しているように見える。
  • しかし、利用者向けとは思えないメッセージが出ている。これはバックエンドのサーバ間通信を想定したメッセージではないか。
  • つまり、Rekoo側のサーバがこのメッセージを受け取って課金成功時の処理をするのが本来の姿ではないか。
  • メッセージがブラウザに表示されてしまっているということは、Rekoo側のサーバは「課金成功」というメッセージを受け取れていないのではないか。

この推測が正しいとすると、さらに以下のようなことが言えます。

  • 「前回のクレジットカードを使う」の機能は正しく動作していないのではないか。
  • ゼロ側では課金処理が成功するが、Rekoo側でKコインを増やす処理が行われないのではないか。つまり、お金だけ取られて、Kコインは増えないのではないか。

ともあれ、ゼロ側での課金は成功しているように見えます。他人の課金用URLにアクセスした場合であっても、特に認証の機能などはなく、そのままゼロ側の課金処理が実行されるものと考えられます。

これはつまり、第三者に勝手に課金処理を行われてしまうおそれがあるということです。

※しかも、推測が正しければ課金が実行されるのにKコインは増えないので、踏んだり蹴ったりです。いや、たとえKコインが増えたとしても、他人に勝手に課金操作を行われてしまうのは問題ですが。

第2の問題: メールアドレスと電話番号の漏洩

課金用URLにアクセスすると、ゼロ側のフォームに移動します。しかし、それはブラウザのスクリプトの機能が有効になっている場合の話です。通常はスクリプトは有効になっていますが、ブラウザによっては、設定を変更して無効にすることもできます。

スクリプト無効の状態で課金用URLにアクセスすると、真っ白な画面に「submit」というボタンが一つだけ表示されます。

この状態でページを右クリックして「ソースを表示」を行うと、この画面のHTMLが表示されます。以下は、「前回のクレジットカードを使う」で500円の購入を試みた際のHTMLの一部です。ただし、一部を **** で伏せてあります。

<FORM METHOD="POST" ACTION="https://credit.zeroweb.ne.jp/cgi-bin/order.cgi?orders" id="chargeform">

<INPUT TYPE="hidden" NAME="clientip" VALUE="59279">

<INPUT TYPE="hidden" NAME="send" VALUE="cardsv">

<INPUT TYPE="hidden" NAME="custom" VALUE="yes">

<INPUT TYPE="hidden" NAME="sendid" VALUE="*********************2544">

<INPUT TYPE="hidden" NAME="sendpoint" VALUE="***************2206">

<INPUT TYPE="hidden" NAME="money" VALUE="500">

<INPUT TYPE="hidden" NAME="cardnumber" VALUE="8888888888888882">

<INPUT TYPE="hidden" NAME="expyy" VALUE="12">

<INPUT TYPE="hidden" NAME="expmm" VALUE="12">

<INPUT TYPE="hidden" NAME="telno" VALUE="">

<INPUT TYPE="hidden" NAME="email" VALUE="">

<noscript>

<INPUT TYPE="submit" VALUE="submit">

</noscript>

</FORM>

このHTMLは、ゼロ側のサーバにデータを送信するフォームになっています。スクリプトが有効の場合には、この内容が自動的に送信されてゼロ側のサイトに移動します。スクリプト無効の場合には自動送信できないので、利用者が送信ボタンを押す必要があるわけです。

ところでよく見ると、上記のHTMLには "cardnumber" "telno" "email" という名前の値が含まれています。名前から判断すると、それぞれカード番号、電話番号、メールアドレスのデータであるように思えます。"cardnumber" には良く分からない値が既に指定されていますが、"telno" と "email" は空になっています。

思い起こすと、先ほど見たゼロ側の入力フォームには、電話番号とメールアドレスの入力欄がありました。初回の課金操作で電話番号とメールアドレスを入力した後、「前回のクレジットカードを使う」でこの画面を呼び出した場合、ここに電話番号とメールアドレスが入ってくるのではないかと推測できます。

また、先に述べたように、課金用URLのユーザーID部分は自由に変更することが可能で、誰でも任意のユーザーの課金用URLにアクセスすることが可能です。

そこで実際に2つのユーザーIDについて試してみたところ、それぞれ以下のような内容が得られました。これも一部を **** で伏せて掲載します。

<FORM METHOD="POST" ACTION="https://credit.zeroweb.ne.jp/cgi-bin/order.cgi?orders" id="chargeform">

<INPUT TYPE="hidden" NAME="clientip" VALUE="59279">

<INPUT TYPE="hidden" NAME="send" VALUE="cardsv">

<INPUT TYPE="hidden" NAME="custom" VALUE="yes">

<INPUT TYPE="hidden" NAME="sendid" VALUE="*********************d8e5">

<INPUT TYPE="hidden" NAME="sendpoint" VALUE="*****************6363">

<INPUT TYPE="hidden" NAME="money" VALUE="500">

<INPUT TYPE="hidden" NAME="cardnumber" VALUE="8888888888888882">

<INPUT TYPE="hidden" NAME="expyy" VALUE="12">

<INPUT TYPE="hidden" NAME="expmm" VALUE="12">

<INPUT TYPE="hidden" NAME="telno" VALUE="0*********">

<INPUT TYPE="hidden" NAME="email" VALUE="*********@******.net">

<noscript>

<INPUT TYPE="submit" VALUE="submit">

</noscript>

</FORM>

<FORM METHOD="POST" ACTION="https://credit.zeroweb.ne.jp/cgi-bin/order.cgi?orders" id="chargeform">

<INPUT TYPE="hidden" NAME="clientip" VALUE="59279">

<INPUT TYPE="hidden" NAME="send" VALUE="cardsv">

<INPUT TYPE="hidden" NAME="custom" VALUE="yes">

<INPUT TYPE="hidden" NAME="sendid" VALUE="*********************eb01">

<INPUT TYPE="hidden" NAME="sendpoint" VALUE="****************9154">

<INPUT TYPE="hidden" NAME="money" VALUE="500">

<INPUT TYPE="hidden" NAME="cardnumber" VALUE="8888888888888882">

<INPUT TYPE="hidden" NAME="expyy" VALUE="12">

<INPUT TYPE="hidden" NAME="expmm" VALUE="12">

<INPUT TYPE="hidden" NAME="telno" VALUE="0*********">

<INPUT TYPE="hidden" NAME="email" VALUE="******@*****.org">

<noscript>

<INPUT TYPE="submit" VALUE="submit">

</noscript>

</FORM>

ここでは****で伏せてありますが、実際には、telnoとemailには実在する電話番号とメールアドレスとおぼしき値が入っていました。

2回試したのは、値がダミーでないことを確認するためです。2回とも同じ値だった場合、たとえば「課金代行会社から提供されたテスト用の値を埋め込んだまま忘れていた」というようなケースが考えられます。今回はそれぞれ異なる値になっているため、利用者が入力したものが表示されていると判断しました。また、cardnumberの値については全ユーザーで共通の値 "8888888888888882" が指定されているため、これは実際のカード番号ではないと判断できます。

つまり、これによって、他人の電話番号とメールアドレスを見ることができたということになります。ただし、カード番号を見ることはできませんでした。

※なお、sendidとsendpointという値がありますが、これはランダムに生成された値のようで、ユーザーごとに異なります。ゼロ側にはmixiのユーザーIDは渡されておらず、これらの値でユーザーを管理しているのでしょう。秘密情報なのかどうかは良く分かりませんが、他人に知られると良くないことが起きる可能性もありますので、前半を **** で伏せて掲載しました。

まとめ

問題点のまとめ

簡単にまとめると、以下のようになります。

  • 課金用URLには秘密情報が含まれておらず、他人の課金用URLを推測することは容易だった。
  • 他人の課金用URLにアクセスしようとした場合でも認証などは何もなく、そのままアクセスでき、課金処理が実行された。
  • 課金用URLのソースに、メールアドレスと電話番号の情報が出力されていた。

現在では、課金用URLが複雑なものに変更されています。また、「前回のクレジットカードを使う」という選択肢そのものがなくなっています。

攻撃方法

攻撃のシナリオも簡単にまとめておきます。以下のような手順で、メールアドレスと電話番号を取得することが可能でした。

  • サンシャイン牧場の公式コミュニティにアクセスして、課金を利用した人の書き込みを探す。
  • ニックネーム部分からユーザーIDを取得する。
  • ブラウザのスクリプトを無効にし、このURLにアクセス: http://mxfarm.rekoo.com/zerotransfer/?uid=(取得したユーザーID)&money=500&cf=old
  • ソースを表示すると、電話番号とメールアドレスが書かれている。

攻撃と言うほど大それたものではなく、他人の課金用URLに普通にアクセスできたというだけです。なお、当然ですが、現在ではこのようにしても何も表示されません。

アナウンス・報道

各社のアナウンスや報道をまとめておきます。順不同です。

よくある疑問と答え

mixiのコミュニティ等で出ていた疑問について、分かる範囲で補足します。

「情報セキュリティ早期警戒パートナーシップ」とは何ですか?

本件は、「情報セキュリティ早期警戒パートナーシップ」の制度を利用してIPAに届出を行ったものです。制度については、「情報処理推進機構:情報セキュリティ:情報セキュリティ早期警戒パートナーシップガイドライン (www.ipa.go.jp)」を参照してください。

なお、このガイドラインに法的な強制力はありません。「法律」であるかのような書き込みをされている方もいらっしゃいましたが、単なるガイドラインに過ぎません。あくまで、関係者の善意によって運用される制度です。

課金を1度しか利用していませんが、対象でしょうか?

情報の露出に関しては、課金を利用した人すべてが対象です。本人が「前回のクレジットカードを使う」を選択したことがあるかどうかは関係ありません。

「1度だけ利用した人は対象外」という情報も流れていたようですが、それは誤課金問題との混同でしょう。「前回のクレジットカードを使う」を選択した際の動作が正しく実装されていなかったため、2度目以降の課金を利用するとうまく処理されないという問題がありました。この問題については、1度しか利用していなければ影響を受けません。

もっとも、今回のケースの場合、第三者が2度目の課金を行うことも可能だったと考えられます。そのため、自身が「1度しか利用していない」と思っていても誤課金の対象になっている可能性があります。いずれにしても、課金を利用した人全員が対象ということです。

課金後にアプリを削除しましたが、対象でしょうか?

アプリの削除は関係ありません。mixi上の操作でアプリを削除しても、Rekooのサーバのデータは消えないからです。

ちなみに牧場のデータも消えずに残ります。アプリを一度削除してから再登録すると、以前の続きから再開されます。今のところ、データを消す方法は無いようです。

mixiの外部から攻撃可能だったのでしょうか?

課金用URLはRekooのサーバのもので、mixi内部のものではありませんでした。mixiにログインしていない状態でもアクセス可能でした。

しかし、mixiの会員でないと、他人のユーザーIDを知るのは難しいかも知れません。

実際に漏洩があったかどうかRekooにも分からないという話がありましたが、どういう事でしょうか?

Rekooは「見える状態だった」ことは明確に発表していますが、実際に漏洩があったかどうかについては発表していません。これは隠していると言うより、純粋に分からないのだと思います。

一般的に、脆弱性を突いた不正アクセスによって情報漏洩が起きたような場合、アクセスの記録 (アクセスログ) を調査することで漏洩の有無を調べることができます。それは、攻撃の際に通常とは異なる記録が残るためです。

しかし今回の問題では、ログから異常を検出することはほとんど不可能です。攻撃が行われた場合、以下のようなURLへのアクセスが記録されるはずです。

http://mxfarm.rekoo.com/zerotransfer/?uid=182754&money=500&cf=old

しかし、この記録があるからといって攻撃されたとは限りません。このURLにアクセスがあること自体は正常だからです。このアクセスは、私 (ユーザーID:182754の会員) が普通に課金の操作を行ったものかもしれませんし、他の誰かが uid=182754 を指定してアクセスしたものかもしれません。どちらなのかは、この記録を見ただけでは分かりません。

今回の問題は「特殊な方法でアクセスできた」とか「本来アクセスされないはずのURLにアクセスされた」というような話ではなく、「普段使われるURLに誰でもアクセスできるようになっていた」という話なのです。ログを見ても、漏洩があったかどうかは簡単には判断できないでしょう。

セッションIDを指定するとカード番号が取れるという話が出ていたようですが?

まず、本件で言う「ユーザーID」は、ユーザーごとにずっと固定の値です。セッションごとに変化するセッションIDとは異なるものです。

本件にはセッションIDは関係ありません。そもそも認証が全く行われていなかった状態であり、セッションハイジャックなども不要です。

セッションID云々の不具合があるという話も流れていたようですが、私は確認していません。単なる噂に過ぎないのかもしれませんし、本件とは別に何かあるのかもしれませんが、わかりません。

Rekoo側でSSLが使われていないのは問題ないのでしょうか?

ゼロ側のフォームのURLが https: で始まっているのに対して、Rekoo側の課金用URLは http: で始まっています。これは、課金用URLがHTTPSではない (SSL/TLSで暗号化されていない) ということです。2009年11月23日現在でもそうなっています。

しかし、現在では課金用URLでメールアドレスや電話番号が出力されることはありませんので、大きな問題ではないようにも思います。そもそも、mixiアプリ自体が https: ではありませんし。

人気のページ

最近の日記

関わった本など

デザイニングWebアクセシビリティ - アクセシブルな設計やコンテンツ制作のアプローチコーディングWebアクセシビリティ - WAI-ARIAで実現するマルチデバイス環境のWebアプリケーション体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践ウェブの仕事力が上がる標準ガイドブック 5 WebプログラミングWeb Site Expert #13Dreamweaver プロフェッショナル・スタイル [CS3対応] (Style for professional)友井町バスターズ (富士見ファンタジア文庫)

その他サイト