検索
連載

UDIDにおけるセキュリティ&プライバシー問題デジタル・アイデンティティ技術最新動向(5)(2/2 ページ)

これまでの連載では「OAuth」と「OpenID Connect」について紹介してきましたが、今回は少し趣向を変えて、UDIDについてお話しします。

PC用表示 関連情報
Share
Tweet
LINE
Hatena
前のページへ |       

UDID代替の識別子

 最近では、アップルがAppStoreの審査時にUDIDを取得するアプリをrejectするようになった影響もあり、UDIDの代わりにUUID(Universally Unique Identifier)と呼ばれる、端末に直接は結び付かない識別子を用いてかんたんログインを実現するケースも増えてきているようです。

 またiOS 6.0からは、ベンダ向けデバイス識別子(identifierForVendor)広告事業者向けデバイス識別子(advertisingIdentifier)というものも登場しました。

 前述したUDIDのセキュリティ上の問題を理解した開発者が、UDIDの代替としてこれらの識別子を用い、かんたんログインを実装するケースも増えてきているようですが、残念ながらこれで問題が解決するというわけではありません。ここでは続けて、これらの識別子が抱えるセキュリティ上の問題について見ていくことにします。

UUID

 UUIDは、グローバルに一意であることが保証された識別子の総称で、iOSでは以下のコードで取得することができます。

// iOS 6.0以降限定
NSString uuid = [[NSUUID UUID] UUIDString];
// iOS 5.x以前でも利用可能
CFUUIDRef uuidRef = CFUUIDCreate(nil);
NSString *uuid = (NSString*) CFUUIDCreateString(nil, uuidRef);

 これらのコードで得られるUUIDは、上記のコードを実行するたびに別の値になりますが、アプリの初回起動時にUUIDを生成&永続化し、それ以降は保存された値をUDIDの代わりに使うことができます。

 UUIDをかんたんログインのために利用すると、

  • UDIDと異なり、アプリごとに異なる識別子が生成される
  • iCloud経由でUUIDを他の端末と共有することで、デバイスをまたがったユーザー識別にも利用できる

などの利点もあります。一方で、一度アプリが削除されてしまうと同じ値を生成することはできないため、PCやiCloudなどにバックアップを取っていない限り、アプリを削除されてしまうとアカウントを復帰できなくなるといった問題も発生します。

ベンダ向け識別子(identifierForVendor)

 iOS 6.0では、以下のコードで、特定ベンダが提供する複数アプリ間で共通な識別子を取得することができます。

NSString vendorIdentifier = [[UIDevice currentDevice].identifierForVendor UUIDString];

 この識別子は特定ベンダの提供するアプリ間で共有され、それらのすべてのアプリが端末から削除されるまで不変です。自社が提供するすべてのアプリにまたがったアクセス解析サービスなどでの利用が想定されます。同じベンダが提供する複数のアプリにまたがってユーザー情報を共有したい場合などに、UUIDの代わりに使われるというようなケースが多いのでしょうか。

 ただし、UUIDと異なりidentifierForVendorは端末にひも付いた識別子であるため、これをかんたんログインに用いる場合は、デバイスをまたいだユーザー識別は行えません(UUID同様、identifierForVendorをiCloud経由でシェアすることは可能ですが、その場合、iOSが保証する「同一ベンダに限って同一の値を返す」という性質が失われるケースがあります)。

広告事業者向け識別子(advertisingIdentifier)

 こちらもiOS 6.0以降で利用できる識別子で、以下のコードで取得できます。

include <AdFramework/AdFramework.h>
NSString advertisingIdentifier = [[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString];

 こちらはidentifierForVendorと異なり、特定デバイス上のすべてのアプリで共通の値となり、ユーザーがデバイス自体を初期化するまでは不変なため、UDIDとよく似た性質を持ちます。UDIDとの違いは、iOS自体にオプトアウトの仕組みが組み込まれており、アプリ側でアプトアウトされているかどうかチェックできることくらいでしょう。

 この識別子はあくまで、広告事業者がユーザーの同意の下でトラッキングを行うために提供されているものです。従って、これをかんたんログインに用いることはできません。

セキュアな「かんたんログイン」のための認証トークンに必要な要素とは?

 ここまで、UDIDを使ったかんたんログインのセキュリティ上の問題を紹介してきました。またUDID代替の識別子として、UUIDやiOS 6.0以降に登場したidentifierForVendor、advertisingIdentifierを紹介しました。

 ここからは、これらの識別子を「認証トークン」として用いた時に、それぞれの識別子の特徴によりどんなセキュリティ上の問題が生まれるのかを、少し一般化して見ていきましょう。

 また、所々でOAuth 2.0のAccess TokenやOpenID ConnectのID Tokenとの比較も行います。これまでの連載第1回〜第4回の記事も参考にしながら読み進めてください。

認証トークンに必要な条件

 ある文字列を認証トークンとして利用するためには、さまざまな条件を満たす必要があります。どのような条件を満たす必要があるかは、以下の資料などを参考にするとよいでしょう。

【関連リンク】

OpenID Connect Messages 1.0 - Security Considerations

http://openid.net/specs/openid-connect-messages-1_0.html#security_considerations

Work item: X.1254 (ex X.eaa) - ITU-T Work Programme

http://www.itu.int/itu-t/workprog/wp_item.aspx?isn=6842


 本稿ではそれらすべてについては述べませんが、以下のような主な条件について考えてみます。

  1. そのトークンは、行使者しか知らないor作成できないものであること
  2. そのトークンは、リプレイ攻撃ができないこと
  3. そのトークンは、書き換え攻撃ができないこと

 また上述の資料とは別に、以下の条件についても考えます。

 4. そのトークンが漏えいした場合、別のトークンを新たに発行できること

 さて、UDIDやUUIDはこれらの条件を満たしているでしょうか?

そのトークンは、行使者しか知らないor作成できないものであること

 UDID(とadvertisingIdentifier)は、同一デバイス上のすべてのアプリが同一の値を得るため、「トークンを行使者しか知らない」という条件を満たすことはできません。また、Jailbreakすればデバイス自体のUDIDを書き換えることができるため、「トークンを行使者しか作成できない」という条件も満たしません。

 これらのことから、UDID(とadvertisingIdentifier)は認証トークンとしては使えないことが分かります。

 UUIDはその端末上のそのアプリ内でのみ利用されるため、セキュアに保存&通信する限りは「トークンを行使者しか知らない」という条件を満たします。

 identifierForVendorも、そのベンダのすべてのアプリがそれをセキュアに扱っている限りは、「行使者しか知らない」という条件を満たすものとして考えてよいでしょう。

 ただしidentifierForVendorはUUIDと比べて共有範囲が広く、それらがすべてデバイスから削除されない限りはリセットされない(lifetimeが長い)ため、UUIDに比べ、漏えいのリスクは高くなります。

【関連リンク】

マイナンバーとプライバシー:識別子と超過リスク

http://www.sakimura.org/2012/10/1829/


 一方でOAuth 2.0のAccess Tokenは、基本的にはそれを発行されたアプリにのみ渡され、他のアプリにその値が漏えいすることはありません。またAccess TokenはOAuth Serverのみ生成可能な文字列であり、攻撃者が有効なトークンを作成することはできません。よってOAuthのAccess Tokenは、「トークンを行使者しか知らない」「トークンを行使者しか作成できない」といった条件を満たします。

 OpenID ConnectのID Tokenは、Cookieに保存するなどのユースケースも想定されているため、ユースケースによっては必ずしも「トークンを行使者しか知らない」という条件を満たすわけではありません。そのためトークンに発行者の署名が付けられており、「トークンを行使者しか作成できない」といった条件を満たすようになっています(「トークンを行使者しか知らない」という条件を満たす使い方をすることも可能です)。

そのトークンは、リプレイ攻撃ができないこと

 攻撃者が被害者のデバイスから送信されたある正常なリクエストの内容を傍受し、リクエストに含まれる認証情報をそのままコピーして利用することで不正にログインする攻撃手法を「リプレイ攻撃」といいます。たとえ認証情報自体が暗号化されていても、暗号化された結果が常に同一値に固定される場合、リプレイ攻撃を受ける可能性があります。

 リプレイ攻撃を防ぐには、「nonce」と呼ばれるワンタイムトークンを使う方式が一般的です。nonceを含んだリクエストに署名を掛け、リクエストを受けた側が一定期間内に同じnonceを含むリクエストを拒否することで、リプレイ攻撃を防ぎます。

 ところがかんたんログインは、リクエスト署名の利用などを想定した仕組みではありません。従って、かんたんログインの識別子としてUDIDやUUIDを利用しても、リプレイ攻撃を防ぐことはできません。かんたんログインを使いつつリプレイ攻撃を防ぐには、かんたんログインとは別にリクエスト署名の仕組みを実装し、nonceを利用できるようにする必要があります。

 また、リクエスト署名のための秘密鍵をアプリ自体に埋め込んでしまうと、攻撃者と被害者どちらのデバイスでも同じ鍵が利用されてしまい、攻撃者が容易にリプレイ攻撃に使える認証情報を得ることになるため、インストールごとに異なる鍵を配送する必要があります。そうなると鍵配送のために新たな認証の仕組みが必要になるため、OAuthのような仕組みが必要になるでしょう(それはもはや「かんたんログイン」といわれる、ユーザーが明示的なログインを行うことなく認証を完結させるという方式ではなさそうですね)。

 なお、OAuth 2.0のAccess Token(Bearer Token)もこの条件を満たしてはいません。OAuth 2.0のBearer Token Profileにはリクエスト署名が存在しないため、nonceを利用することもできません。

 一方OpenID ConnectはID Tokenの検証のためにnonceの利用を可能(Implicit Flowの場合は必須)にしています。そのためOpenID ConnectのID Tokenは、「そのトークンは、リプレイ攻撃ができないこと」という条件を満たします。

そのトークンは、書き換え攻撃ができないこと

 UDIDは、前述のようにJailbreakにより書き換えが可能なため、この条件も満たしません。

 UUIDに関しては、それをセキュアストレージ(iOSの場合はKeyChain)に保存している限り、書き換えられる恐れはないでしょう。しかしiOSのUserDefaultsのように保護されていないストレージ領域に保存された場合には、漏えいおよび書き換えの危険があります。これらはOAuth 2.0のAccess TokenやOpenID ConnectのID Tokenについても同様です。

 OAuth 2.0およびOpenID Connectについては、トークンが外部サービスからHTTP Redirect経由で渡される(iOSアプリからImplicit Flowを利用する場合)ため、そのリダイレクトレスポンスを書き換えられる可能性もあります(トークン置換攻撃)。OAuth 2.0のリダイレクトレスポンスを書き換えられ、リダイレクトURLに含まれるAccess Tokenをそのままサーバサイドでも使ってしまうことで発生するのが、連載第2回の「スマホアプリでのFacebook IDでログインには注意!」の章で紹介した脆弱性です。

 OAuth 2.0の場合は、そのAccess Tokenが自分自身に対して発行されたものであることを各OAuth Clientが検証できれば、トークン置換攻撃を防ぐことができます。ただしOAuth 2.0自体にはそのような検証の仕組みは定義されていないため、別途、トークン検証の仕組みを用意する必要があります。

 OpenID ConnectのID Tokenは、トークンに発行者の署名付きで発行先が明記されているため、仕様通りにトークンを検証するだけでトークン置換攻撃を防ぐことができます。

そのトークンが漏えいした場合、別のトークンを新たに発行できること

 UDIDは端末にひも付いているため、漏えいしたからといって別のUDIDに置換することは不可能です。端末上で生成されるUUID、identifierForVendorについても、漏えい後にアカウント情報を引き継いだまま該当ユーザーに別の値を割り振るには、それらの識別子以外の認証方法が必要になります。

 よってこれらを(明示的なログインやユーザー登録を伴わない)かんたんログインのために使う以上は、「そのトークンが漏えいした場合、別のトークンを新たに発行できること」という条件は満たしません。かんたんログインを維持したままこの条件を満たすことは不可能でしょう。

 一方OAuth 2.0やOpenID Connectは、OAuthサーバがユーザーを認証できることを前提としているため、トークンが漏えいしても、古いトークンを破棄してもう一度ユーザーをOAuthサーバに送り、新たなトークンを取り直すことができます。よってOAuth 2.0のAccess TokenやOpenID ConnectのID Tokenは、「そのトークンが漏えいした場合、別のトークンを新たに発行できること」という条件を満たします。

UDIDにおけるセキュリティ問題のまとめ

 ここまで、UDIDを使ったかんたんログインが抱えるセキュリティ上の問題を皮切りに、UUIDやiOS 6.0から追加されたidentifierForVendorについても、「認証トークン」としての利用可能性を見てきました。

 結論としては、それらのいずれも「認証トークン」が果たすべき条件をすべて満たせるものではありません。それらを利用してかんたんログインを実現する限り、なりすましの危険性や漏えい後のアカウントリカバリが不可能であるなどの限界が見えてきました。

 一方で、現実問題としてユーザー登録による離脱率の上昇を抑えたいなどの理由で、それらの識別子を用いたかんたんログインを依然として選択するケースもあるかと思います。iOS上のゲームアプリなどでは、端末をまたげなかったり、アプリを消すとそれまでのデータがすべて消えてしまうなどの挙動に対する共通認識もある程度共有されているようです。そういったケースにおいてまでかんたんログインの利用を否定するべきかどうかというと、筆者にはまだ疑問が残ります。

 ただ、そういった場合にも、その選択によってどのようなリスクや制約条件が発生するのかはきちんと理解してほしいと思います。

 さて、今回はUDIDのセキュリティ上の問題点を紹介しましたが、次回はUDIDのプライバシー上の問題を見ていきたいと思います。

著者プロフィール

Nov Matake

http://matake.jp

OpenID Foundation Japan Evangelist。個人では、OAuth.jpというサイトを通じて日本語でのOAuthに関する情報発信などを行ったり、OpenID ConnectやOAuth 2.0のRubyライブラリを開発している。


Copyright © ITmedia, Inc. All Rights Reserved.

前のページへ |       

Security & Trust 記事ランキング

ページトップに戻る