ParseっていうBaaSのソーシャル連携の実装がよくなった気がする

もう少しでおはようございます、ritouです。

前にこんなの書いたわけです。
ParseっていうBaaSのソーシャル連携の実装がよろしくない気がする - r-weblife

内容はこんな感じです。

  • ParseっていうBaaSのTwitter連携について
  • アプリはParseに対してConsumerKey/Secret, Token/Token Secretを渡してTwitterアカウントとの連携を行う
  • "攻撃者がTwitterに登録したConsumerKey/Secretとそれを使って取得した誰かのToken/Token Secretの組み合わせを持っていれば、好き勝手にアカウント連携とかログインとかできる"という問題がありそう

で、前回私の調査が足りなかったのかその対応が行われたのか定かではありませんが、アプリ開発者の設定により上記の問題への対策ができることに気付きましたので整理しておきます。
まずは、Parseの設定画面を見てみます

https://www.parse.com/apps から自分の登録したアプリを選択します。
そして、上の方のメニューからSettingsを選択します。
左のところからUserAuthenticationを選択します。

ユーザー認証に関して、利用するパターンを制限したりできます。

  • Enable new authentication methods by default : 知らんがな
  • Allow username and password-based authentication : パスワードでログインさせるかどうか
  • Allow anonymous users : 匿名ユーザー?知らんがな

まぁ、細かいところは後で調べるとして、今回注目したところは、FacebookTwitterの連携の部分にはClient(Consumer)IDの入力欄があることです。

とりあえず、ここに登録しておけば
"異なるConsumer向けのCredential達をREST APIに投げられたとしてもチェックできる!"
ということでTwitter部分で前回と同じ検証をしてみます。
ConsumerKey(TwitterはOAuth 1.0aなので)を設定していない状態で同じことをやります。

試したこと(再掲)

ParseをBackendとして利用するアプリをParseアプリと呼びます.

(1) TwitterにアプリケーションAを登録
(2) アプリケーションA経由のTwitterのアカウントを用いてParseアプリに新規アカウント登録する
(3) アプリケーションA経由のTwitterのアカウントを用いてParseアプリにログインする
(4) TwitterにアプリケーションBを登録
(5) アプリケーションB経由のTwitterのアカウントを用いてParseアプリに・・・
Twitter上のユーザーは普段から使ってる1つのアカウントとします.
TwitterのOAuth Clientが2つあって、それぞれを経由したアカウントでParseアプリの新規アカウント登録/ログインしようとするとどうなるかという話です.

前回のエントリでは、アプリケーションA,Bに関わらず同じユーザーとして扱われてしまいました。
つまり、悪意のあるTwitter OAuth利用開発者が手元のToken情報などをParseアプリに投げることで

試した結果

まずは、TwitterのOAuthを利用するアプリケーション Aが取得したTokenなどを用いてログインを試みます。

curl -X POST \
  -H "X-Parse-Application-Id: (Parseから発行されたApplication ID)" \
  -H "X-Parse-REST-API-Key: (Parseから発行された REST-API-Key)" \
  -H "Content-Type: application/json" \
  -d '{
        "authData": {
          "twitter": {
            "id": "14197251",
            "screen_name": "ritou",
            "consumer_key": "アプリケーションAのConsumer Key",
            "consumer_secret": "アプリケーションAのConsumer Secret",
            "auth_token": "アプリケーションAが受け取ったAccess Token",
            "auth_token_secret": "アプリケーションAが受け取ったAccess Token Secret"
          }
        }
      }' \
  https://api.parse.com/1/users

前回と同様のusername, objectIdなどが返されます.

{
  "username":"bz...",
  "createdAt":"2012-05-xxTxx:xx:xx.xxxZ",
  "updatedAt":"2012-05-xxTxx:xx:xx.xxxZ",
  "objectId":"NO...",
  "sessionToken":"12...",
  "authData":{(略)}
}

次に、もう一つ作っておいたTwitterのOAuthを利用するアプリケーション Bが取得したTokenなどを用いてログインを試みます。
この時に、X-Parse-Application-Id, X-Parse-REST-API-Keyは同じものを利用します。

curl -X POST \
  -H "X-Parse-Application-Id: (Parseから発行されたApplication ID)" \
  -H "X-Parse-REST-API-Key: (Parseから発行された REST-API-Key)" \
  -H "Content-Type: application/json" \
  -d '{
        "authData": {
          "twitter": {
            "id": "14197251",
            "screen_name": "ritou",
            "consumer_key": "アプリケーションBのConsumer Key",
            "consumer_secret": "アプリケーションBのConsumer Secret",
            "auth_token": "アプリケーションBが受け取ったAccess Token",
            "auth_token_secret": "アプリケーションBが受け取ったAccess Token Secret"
          }
        }
      }' \
  https://api.parse.com/1/users

先ほどのParseの設定画面でアプリケーションAのConsumerKeyを登録しておいた場合、
アプリケーションBのConsumerKeyとの比較が行われて以下のようなレスポンスを受け取りました。

{"code":251,"error":"Unacceptable Twitter consumer key."}[

これで、
ParseがTwitterのConsumerKeyのチェックを行い、アプリ開発者が登録済のConsumerKey以外ではTwitter連携(ログインなど)ができないことが確認できました。

※2011/06/03追記:
異なるConsumerKeyのCredential一式でTwitter連携機能が使えないことはわかりましたが、下記の件については未だ気に入らない点なのであります。

  • ConsumerSecretをParseアプリに持っている必要があり、しかもParseプラットフォームに渡すこと
  • Twitter OAuth時にParseにデータを渡すことについて同意をもらってるかどうかとか

Facebookの方はどうか

次はFacebookの方も調べてみたいところです。
Facebookの方では次のように、ユーザーID,OAuth 20のアクセストークン、有効期限をParseプラットフォームに渡します。
https://www.parse.com/docs/rest#users-linking

{
  "facebook": {
    "id": "user's Facebook id number as a string",
    "access_token": "an authorized Facebook access token for the user",
    "expiration_date": "token expiration date of the format: yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
  }
}

Twitterのケースと異なるところがあります。

  • Facebook は OAuth 2.0 + Bearer Tokenなので、リソースアクセスにはAccess Tokenのみが必要
  • Facebookは/appというAPIAccess TokenがどのClient IDのものかを確認できる

ということで、開発者が設定画面でClient IDを指定し、Parseプラットフォーム側がFacebookの/appとかいうAPIをたたいてマッチするか確認するようになっていれば問題ないわけです。
http://oauth.jp/oauth-20-implicit-flow の最後のあたりをParseがやってくださいということです。

この検証は次回に回しましょう。
ではまた!