一意の識別子に関するベスト プラクティス

このドキュメントでは、ユースケースに応じて適切なアプリ ID を選択する方法について説明します。

Android のパーミッションの概要については、パーミッションの概要をご覧ください。Android のパーミッションに関するベスト プラクティスについては、アプリ パーミッションに関するベスト プラクティスをご覧ください。

Android の識別子の使用に関するベスト プラクティス

各種の Android ID を使用する際は、次のベスト プラクティスに沿って行ってください。

  1. ハードウェア ID を使用しない。ほとんどのユースケースにおいて、必要な機能を制限することなく、SSAID(Android ID)などのハードウェア ID を使用しないことを選択できます。

    Android 10(API レベル 29)以降、IMEI やシリアル番号など、リセット不可能な ID に関して制限が追加されています。このような ID にアクセスできるのは、デバイス オーナーまたはプロファイル オーナーのアプリや、特別な携帯通信会社パーミッションを持っているアプリ、READ_PRIVILEGED_PHONE_STATE 特権パーミッションを持っているアプリに限られます。

  2. ユーザー プロファイル作成や広告のユースケースでは広告 ID だけを使用する。広告 ID を使用する際は、必ず広告のトラッキングに関するユーザーの選択を尊重するようにしてください。また、広告 ID と個人情報(PII)をリンクしたり、広告 ID のリセットをブリッジしたりしないようにしてください。

  3. 不正決済防止と電話機能のユースケースを除き、他のすべてのユースケースでは、可能な限りインスタンス ID または非公開環境に保存した GUID を使用する。非広告のユースケースでは、ほとんどの場合、インスタンス ID または GUID だけで十分なはずです。

  4. プライバシーに関するリスクを最小限に抑えるため、ユースケースに適した API を使用する。価値の高いコンテンツの保護には DRM API を、不正行為防止には SafetyNet API を使用します。SafetyNet API は、プライバシー リスクを発生させずにデバイスが正規品であるかどうかを判定できる最も簡単な手段です。

以下のセクションでは、Android アプリの開発時に上記のルールをどのように適用するのかについて詳細に説明します。

広告 ID を使用する

広告 ID は、ユーザーがリセットできる識別子であり、広告のユースケースに適しています。ただし、広告 ID を使用する際は、いくつか注意事項があります。

広告 ID のリセットに関して、必ずユーザーの意図を尊重する。ユーザーの同意なく、ユーザーによるリセットをブリッジする(別の ID やフィンガープリントを使用して新しい広告 ID とリンクする)ことはしないでください。Google Play デベロッパー コンテンツ ポリシーに次のような規定があります。

「リセットが行われた場合に、ユーザーの明示的な同意なしに、新しい広告 ID と、以前の広告 ID や以前の広告 ID から派生したデータとをリンクしてはなりません。」

関連付けられているパーソナライズド広告フラグを必ず尊重する。広告 ID の設定では、その ID に関連付けられているトラッキングの頻度や範囲をユーザーが制限できるようになっています。必ず AdvertisingIdClient.Info.isLimitAdTrackingEnabled() メソッドを使用して、ユーザーが選択した設定が無視されることのないようにしてください。Google Play デベロッパー コンテンツ ポリシーに次のような規定があります。

「ユーザーが指定した [インタレスト ベース広告をオプトアウト] や [広告のカスタマイズをオプトアウトする] の設定を遵守する必要があります。ユーザーがこの設定を有効にした場合は、広告目的でユーザー プロファイルを作成したり、ユーザーをパーソナライズド広告のターゲットに設定したりするために広告 ID を使用してはなりません。広告 ID の使用が許可されるアクティビティは、コンテンツ ターゲット広告や、フリークエンシー キャップ、コンバージョン トラッキング、レポート作成、セキュリティ / 不正行為検出などに限られます。」

広告 ID の使用に関して、使用している SDK に適用されるプライバシー ポリシーやセキュリティ ポリシーに注意する。たとえば、Google アナリティクス SDK の enableAdvertisingIdCollection() メソッドに true を渡す場合、必ず、適用されるすべてのアナリティクス SDK ポリシーを確認し遵守するようにしてください。

また、Google Play デベロッパー コンテンツ ポリシーは、広告 ID を「個人情報にリンクしたり、永続的なデバイス ID(SSAID、MAC アドレス、IMEI など)に関連付けたりしない」ことを求めています。

たとえば、情報を収集してデータベース テーブルの次の列に入力しようとしている場合を考えてみましょう。

TABLE-01
timestamp ad_id account_id clickid
TABLE-02
account_id name dob country

この例の場合、両方のテーブルの account_id 列を使用することで、ad_id 列と PII を関連付けることができます。ただし、ユーザーの明示的なパーミッションなくこの処理を行うと、Google Play デベロッパー コンテンツ ポリシーに違反することになります。

広告主 ID と PII の関係付けは、この例ほど単純ではない場合もあります。PII と広告 ID をキーとするテーブルの両方に「疑似識別子」が存在する可能性があり、そのことによって問題が発生することもあります。たとえば、TABLE-01 と TABLE-02 を次のように変更するとします。

TABLE-01
timestamp ad_id clickid dev_model
TABLE-02
timestamp demo account_id dev_model name

この場合は、クリック イベントがごくまれにしか発生しなかったときに、イベントのタイムスタンプとデバイスモデルを使用して TABLE-01 の広告主 ID と TABLE-02 の PII が関連付けられる可能性があります。

多くの場合、データセットにこのような疑似識別子が一切存在しないようにすることは困難ですが、関連付けが発生する明らかなリスクがある場合については、できる限り一意のデータを一般化することによってリスクを回避できます。この例では、タイムスタンプの精度を低下させると、同じモデルの複数のデバイスが同じタイムスタンプで存在することになります。

他にも次のような解決策が考えられます。

  • PII と広告 ID を明示的にリンクするようなテーブル設計は行わない。上記の最初の例でいえば、TABLE-01 に account_id 列を含めないようにします。

  • 広告 ID をキーとするデータと PII の両方にアクセスできるユーザーやロールのアクセス制御リストを分離してモニタリングする。たとえば、テーブル間を結合するなどして、両方のソースに同時にアクセスできる能力を厳格に管理、監査することで、広告 ID と PII の間の関連付けが発生するリスクを軽減できます。一般に、アクセス制御では次のことを行います。

    1. 広告主 ID をキーとするデータ用と PII 用の各アクセス制御リスト(ACL)を相互に関連付けないように維持し、両方の ACL に含まれるメンバーやロールの数を最小限に抑える。
    2. アクセスログ作成と監査の機能を実装し、ルールの例外を検知して管理する。

責任を持って広告 ID を扱う方法については、AdvertisingIdClient API リファレンスをご覧ください。

インスタンス ID や GUID を使用する

デバイス上で実行されているアプリのインスタンスを特定する方法としては、インスタンス ID が最もわかりやすく、広告以外の大多数のユースケースではこの方法をおすすめします。インスタンス ID にアクセスできるのは、割り当てられたアプリ インスタンスだけに限られます。また、インスタンス ID は、アプリがインストールされている間しか存続しないため、比較的簡単にリセットできます。

そのため、インスタンス ID は、リセット不可能なデバイスレベルのハードウェア ID に比べて、優れたプライバシー特性を備えています。詳細については、FirebaseInstanceId API リファレンスをご覧ください。

インスタンス ID を使用することが実用的でないケースでは、カスタム GUID(Globally-Unique ID)を使用してアプリ インスタンスを一意に識別することもできます。最も簡単なのは、次のコードを使用して独自の GUID を作成する方法です。

Kotlin

    var uniqueID = UUID.randomUUID().toString()
    

Java

    String uniqueID = UUID.randomUUID().toString();
    

この ID はグローバルに一意であるため、特定のアプリ インスタンスを識別する際に使用できます。複数のアプリ間での識別子の関連付けによる問題を避けるため、GUID は外部(共有)ストレージではなく内部のストレージに保存します。詳細については、データとファイルのストレージの概要をご覧ください。

MAC アドレスは使用しない

MAC アドレスはグローバルに一意であり、ユーザーはリセットできず、デバイスを初期化しても失われることはありません。そのため、通常、ユーザー ID として MAC アドレスを使用することは推奨されません。Android 10(API レベル 29)以降を搭載しているデバイスは、デバイス オーナー アプリではないすべてのアプリに対して、ランダム化された MAC アドレスをレポートします。

Android 6.0(API レベル 23)から Android 9(API レベル 28)までの場合、Wi-Fi や Bluetooth など、ローカル デバイスの MAC アドレスをサードパーティ API で使用することはできません。WifiInfo.getMacAddress() メソッドと BluetoothAdapter.getDefaultAdapter().getAddress() メソッドはいずれも 02:00:00:00:00:00 を返します。

また、Android 6.0 から Android 9 までの場合、Bluetooth や Wi-Fi のスキャンで検出された付近の外部デバイスの MAC アドレスにアクセスするには次のパーミッションが必要です。

メソッド / プロパティ 必要なパーミッション
WifiManager.getScanResults() ACCESS_FINE_LOCATION または ACCESS_COARSE_LOCATION
BluetoothDevice.ACTION_FOUND ACCESS_FINE_LOCATION または ACCESS_COARSE_LOCATION
BluetoothLeScanner.startScan(ScanCallback) ACCESS_FINE_LOCATION または ACCESS_COARSE_LOCATION

識別子の特性

Android OS では、動作特性の異なるさまざまな ID を使用できます。どの ID を使用するべきかは、以下の特性に基づいて、ユースケースに応じて判断します。ただし、各特性にはプライバシー上のリスクもあるため、特性同士の相互の関係を理解する必要があります。

スコープ

識別子のスコープとは、どのシステムがその識別子にアクセスできるかということです。通常、Android 識別子のスコープは次の 3 種類に分類されます。

  • 単一アプリ: 識別子はアプリの内部に存在し、他のアプリからはアクセスできません。
  • アプリグループ: 所定の関連アプリグループからアクセスできます。
  • デバイス: デバイスにインストールされたすべてのアプリからアクセスできます。

識別子に割り当てられたスコープが広いほど、識別子がトラッキングのために使用されるリスクが高くなります。反対に、単一のアプリ インスタンスからしかアクセスできない識別子であれば、複数のアプリでの複数のトランザクションを対象としたデバイスのトラッキングに使用することはできません。

リセット可能性と永続性

リセット可能性と永続性は、識別子の使用期間を定義し、識別子をリセットする方法を指定するものです。一般にリセットのトリガーとなるイベントは、アプリ内リセット、システム設定を介したリセット、起動時のリセット、インストール時のリセットなどです。Android の識別子の使用期間はさまざまですが、通常は ID のリセット方法と連動しています。

  • セッションのみ: ユーザーがアプリを再起動するたびに新しい ID が使用されます。
  • インストール リセット: ユーザーがアプリをアンインストールして再インストールするたびに新しい ID が使用されます。
  • FDR リセット: ユーザーがデバイスを初期化するたびに新しい ID が使用されます。
  • FDR 後存続: デバイスを初期化しても ID は失われません。

リセットできる場合、ユーザーは既存のプロファイル情報との関連付けが解除された新しい ID を作成できます。初期化後も存続する識別子など、識別子が存続する期間が長くなり安定性が高くなるほど、ユーザーが長期にわたるトラッキングの対象とされるリスクが高まります。アプリの再インストール時に識別子がリセットされる場合は、アプリ内やシステム設定からユーザーが明示的に識別子をリセットする手段がなくても、識別子の永続性が低くなり、ID をリセットする手段が提供されることになります。

一意性

一意性は、競合(対象のスコープ内に同一の ID が存在すること)の可能性を示します。一意性が最高レベルの GUID(Globally-Unique ID)の場合、他のデバイスやアプリも含めて競合は発生しません。それ以外の場合、一意性のレベルは、ID のエントロピーや、ID の作成に使用したソースのランダム性に応じて変わります。たとえば、暦上のインストール日(2019-03-01 など)に基づいて作成したランダム ID は、インストールの Unix タイムスタンプ(1551414181 など)に基づいて作成した ID に比べて、競合が発生する可能性が格段に高くなります。

一般に、ユーザー アカウント ID は一意であると見なすことができます。つまり、デバイスとアカウントの組み合わせによって、一意の ID を生成できます。他方、一定のメンバーを対象とする ID で一意性のレベルが低い場合、個々のユーザーをトラッキングしにくくなるため、プライバシー保護機能が強化されます。

整合性保護と否認防止

なりすましやリプレイ攻撃が難しい ID を使用することで、関連付けられているデバイスやアカウントが特定の特性を持っていることを証明できます。たとえば、対象のデバイスが、スパム送信者の使用している仮想デバイスではないことを証明できます。なりすましが難しい ID は、否認防止性も備えています。デバイスがシークレット鍵を使用してメッセージに署名すると、「他の誰かのデバイスがメッセージを送信した」と主張することは困難になります。否認防止は、ユーザーにとって望ましいものであるとき(決済の認証に使用する場合など)もあれば、望ましくないものであるとき(送信すべきでないメッセージを送信してしまった場合など)もあります。

一般的なユースケースと使用すべき識別子

このセクションでは、ハードウェア ID(IMEI など)の代わりに使用できる ID について説明します。ハードウェア ID は、ユーザーがリセットできず、デバイス全体がスコープとなるため、推奨されません。多くの場合、アプリをスコープとする ID で十分です。

ログアウトしたユーザーの設定をトラッキングする

ユーザー アカウントを含まずに、デバイス単位の状態をサーバー側で保存するケースが該当します。

使用する識別子: インスタンス ID または GUID

この ID が推奨される理由

ユーザーが設定をリセットするためにアプリを再インストールする場合があるため、再インストール後も存続する情報を使用することは推奨されません。

ログアウトしたユーザーの設定を、署名キーが同じ複数のアプリでトラッキングする

デバイス単位の状態をサーバー側で保存し、そのデータを、同一のデバイス上にあり同一のキーで署名されている別のアプリに転送するケースが該当します。

使用する識別子: SSAID

この ID が推奨される理由

Android 8.0(API レベル 26)以降では、SSAID によって、同じデベロッパー署名キーで署名されているアプリの間で共通となる識別子が付与されます。そのため、ユーザーがアカウントにログインしなくてもアプリ間で状態を共有できます。

ログアウトしたユーザーの行動をトラッキングする

同一のデバイス上にある複数のアプリやセッションを横断したユーザーの行動に基づいて、ユーザー プロファイルを作成するケースが該当します。

使用する識別子: 広告 ID

この ID が推奨される理由

Google Play デベロッパー コンテンツ ポリシーの規定により、広告のユースケースでは、ユーザーがリセット可能な広告 ID を使用する必要があります。

ログアウトしたユーザーまたは匿名ユーザーの分析を行う

ログアウトしたユーザーや匿名ユーザーの使用状況統計情報を収集、分析するケースが該当します。

使用する識別子: インスタンス ID または GUID(インスタンス ID では不十分な場合)

この ID が推奨される理由

インスタンス ID や GUID は、その ID を作成したアプリがスコープとなるため、複数のアプリを横断してユーザーをトラッキングする目的には使用できないようになっています。また、ユーザーがアプリのデータを消去したりアプリを再インストールしたりすることで簡単にリセットできます。インスタンス ID や GUID は簡単に作成できます。

  • インスタンス ID を作成する: Firebase Cloud Messaging ガイドをご覧ください。
  • GUID を作成する: アプリ内にロジックを実装します。次のコード スニペットをご覧ください。

    Kotlin

        val uniqueID: String = UUID.randomUUID().toString()
        

    Java

        String uniqueID = UUID.randomUUID().toString();
        

「収集するデータは匿名データである」とユーザーに告知しているデベロッパーは、ID と PII(あるいは PII とリンクする可能性のある他の ID)とをリンクさせることがないように注意してください。

また、モバイルアプリ向け Google アナリティクスを使用すると、アプリ単位で分析できるようになります。

ログアウトしたユーザーのコンバージョンをトラッキングする

マーケティング戦略の成否を判断するためにコンバージョンをトラッキングするケースが該当します。

使用する識別子: 広告 ID

この ID が推奨される理由

広告関連のユースケースであり、複数のアプリで使用できる ID が必要となる可能性があるため、広告 ID が最適です。

複数のデバイスでの複数のインストールを処理する

1 人のユーザーが複数のデバイス上に同じアプリをインストールした場合に、アプリ インスタンスを正しく識別する必要があるケースが該当します。

使用する識別子: インスタンス ID または GUID

この ID が推奨される理由

インスタンス ID は、まさにこの目的のために設計されています。スコープがそのアプリに限定されているため、複数のアプリ間でのユーザーのトラッキングには使用できません。また、再インストール時にリセットされます。まれに、インスタンス ID では不十分な場合は、GUID を使用することもできます。

不正行為防止: 無料コンテンツ制限を適用し、シビル攻撃を検知する

無料記事など、デバイス上でユーザーが表示できる無料コンテンツの数を制限するケースが該当します。

使用する識別子: インスタンス ID または GUID。Android 8.0(API レベル 26)以降ではアプリ署名キーをスコープとする SSAID も使用可。

この ID が推奨される理由

GUID やインスタンス ID を使用すると、ユーザーがコンテンツ上限の適用を回避するにはアプリを再インストールしなければならなくなるため、ほとんどのユーザーに思いとどまらせることができます。それでも保護が十分でないという場合は、Android の DRM API を使用できます。APK ごとの識別子である Widevine ID を使用してコンテンツへのアクセスを制限できます。

携帯通信会社の機能

アプリが携帯通信会社アカウントを使用してデバイスの通話機能やテキスト メッセージ機能を利用するケースが該当します。

使用する識別子: IMEI、IMSI、Line1

この ID が推奨される理由

携帯通信会社に関連する機能に必要な場合にはハードウェア識別子の使用が認められます。たとえば、ハードウェア識別子を使用して、他の携帯通信会社や SIM スロットに切り替えたり、IP(Line1 の場合) - SIM ベースのユーザー アカウントで SMS メッセージを送信したりできます。ただし、特権のないアプリの場合は、アカウント ログインを使用してサーバー側でユーザー デバイス情報を取得することをおすすめします。Android 6.0(API レベル 23)以降ではランタイム権限を介してのみハードウェア識別子を使用できるようになっていることも理由の 1 つです。ユーザーがこの権限をオフにする可能性があるため、アプリの方で例外を適切に処理する必要があります。

不正使用の検知: ボットや DDoS 攻撃を特定する

バックエンド サービスを攻撃する複数のフェイク デバイスを検知するケースが該当します。

使用する識別子: SafetyNet API

この ID が推奨される理由

単独の ID では、デバイスが正規のものであるかどうかの判定が難しくなります。エミュレータや、デバイスになりすましたコードではなく、正規の Android デバイスから送信されたリクエストであるか検証するには、SafetyNet API の attest() メソッドを使用して、リクエスト送信元デバイスの信頼性を検証します。詳細については、SafetyNet API ドキュメントをご覧ください。

不正行為や不正使用の検知: 高価値認証情報の盗難を検知する

盗まれた高価値認証情報を使用して 1 つのデバイスが複数回使用されていないか検知するケースが該当します(不正決済など)。

使用する識別子: 不正行為防止には、その性質上、独自のシグナルが必要となり、またそうしたシグナルは時とともに変わる可能性があるため、本書では取り扱いません。ただし、IMEI や IMSI などのハードウェア ID は、root 権限取得済みのデバイスやエミュレート デバイスでは簡単に変更できるため、不正行為の指標としては信頼できません。