| page.title=Best Practices for Unique Identifiers |
| page.metaDescription=How to manage unique identifiers the right way for users. |
| page.tags=ids, user data |
| meta.tags="ids", "user data" |
| page.image=images/cards/card-user-ids_2x.png |
| |
| page.article=true |
| @jd:body |
| |
| <div id="tb-wrapper"> |
| <div id="tb"> |
| <h2>In this document</h2> |
| <ol> |
| <li><a href="#tenets_of_working_with_android_identifiers">Tenets of Working with |
| Android Identifiers</a></li> |
| <li><a href="#version_specific_details_identifiers_in_m">Identifiers in Android 6.0+</a></li> |
| <li><a href="#working_with_advertising_ids">Working with Advertising IDs</a></li> |
| <li><a href="#working_with_instance_ids_&_guids">Working with Instance IDs and GUIDs</a></li> |
| <li><a href="#understand_identifier_characteristics">Understanding Identifier |
| Characteristics</a> |
| <ol> |
| <li><a href="#scope">Scope</a></li> |
| <li><a href="#resettability_&_persistence">Resettability & persistence</a></li> |
| <li><a href="#uniqueness">Uniqueness</h3> |
| <li><a href="#integrity_protection_and_non-repudiability">Integrity protection and |
| non-repudiability</a></li> |
| </ol> |
| </li> |
| <li><a href="#use_appropriate_identifiers">Common Use Cases and the Identifier to Use</a> |
| <ol> |
| <li><a href="#a_track_signed-out_user_preferences">Tracking signed-out user |
| preferences</a></li> |
| <li><a href="#b_track_signed-out_user_behavior">Tracking signed-out user behavior</a></li> |
| <li><a href="#c_generate_signed-out_anonymous_user_analytics">Generating |
| signed-out/anonymous user analytics</a></li> |
| <li><a href="#d_track_signed-out_user_conversion">Tracking signed-out user |
| conversion</a></li> |
| <li><a href="#e_handle_multiple_installations">Handling multiple installations</a></li> |
| <li><a href="#f_anti-fraud_enforcing_free_content_limits_detecting_sybil_attacks">Anti-fraud: |
| Enforcing free content limits / detecting Sybil attacks</a></li> |
| <li><a href="#g_manage_telephony_&_carrier_functionality">Managing telephony and carrier |
| functionality</a></li> |
| <li><a href="#h_abuse_detection_identifying_bots_and_ddos_attacks">Abuse detection: |
| Identifying bots and DDoS attacks</a></li> |
| <li><a href="#i_abuse_detection_detecting_high_value_stolen_credentials">Abuse detection: |
| Detecting high value stolen credentials</a></li> |
| </ol> |
| </li> |
| </ol> |
| </div> |
| </div> |
| |
| <p> |
| While there are valid reasons why your application may need to identify a |
| device rather than an instance of the application or an authenticated user on |
| the device, for the vast majority of applications, the ultimate goal is to |
| identify a particular <em>installation</em> of your app (not the actual |
| physical device). |
| </p> |
| |
| <p> |
| Fortunately, identifying an installation on Android is straightforward using |
| an Instance ID or by creating your own GUID at install time. This document |
| provides guidance for selecting appropriate identifiers for your application, |
| based on your use-case. |
| </p> |
| |
| <p> |
| For a general look at Android permissions, please see <a href= |
| "{@docRoot}training/articles/user-data-overview.html">Permissions |
| and User Data</a>. For specific best practices for |
| working with Android permissions, please see <a href= |
| "{@docRoot}training/articles/user-data-permissions.html">Best Practices for |
| App Permissions</a>. |
| </p> |
| |
| |
| <h2 id="tenets_of_working_with_android_identifiers">Tenets of Working with Android Identifiers</h2> |
| |
| <p> |
| We recommend that you follow these tenets when working with Android |
| identifiers: |
| </p> |
| |
| <p> |
| <em><strong>#1: Avoid using hardware identifiers.</strong></em> Hardware |
| identifiers such as SSAID (Android ID) and IMEI can be avoided in most |
| use-cases without limiting required functionality. |
| </p> |
| |
| <p> |
| <em><strong>#2: Only use Advertising ID for user profiling or ads |
| use-cases.</strong></em> When using an <a href= |
| "https://support.google.com/googleplay/android-developer/answer/6048248?hl=en"> |
| Advertising ID</a>, always respect the <a href= |
| "https://play.google.com/about/developer-content-policy.html#ADID">Limit Ad |
| Tracking</a> flag, ensure the identifier cannot be connected to personally |
| identifiable information (PII) and avoid bridging Advertising ID resets. |
| </p> |
| |
| <p> |
| <em><strong>#3: Use an Instance ID or a privately stored GUID whenever |
| possible for all other use-cases except payment fraud prevention and |
| telephony.</strong></em> For the vast majority of non-ads use-cases, an |
| instance ID or GUID should be sufficient. |
| </p> |
| |
| <p> |
| <em><strong>#4: Use APIs that are appropriate to your use-case to minimize |
| privacy risk.</strong></em> Use the |
| <a href="http://source.android.com/devices/drm.html">DRM |
| API</a> API for high value content |
| protection and the <a href="{@docRoot}training/safetynet/index.html">SafetyNet |
| API</a> for abuse prevention. The Safetynet API is |
| the easiest way to determine whether a device is genuine without incurring |
| privacy risk. |
| </p> |
| |
| <p> |
| The remaining sections of this guide elaborate on these rules in the context |
| of developing Android applications. |
| </p> |
| |
| <h2 id="version_specific_details_identifiers_in_m">Identifiers in Android 6.0+</h2> |
| |
| <p> |
| MAC addresses are globally unique, not user-resettable and survive factory |
| reset. It is generally not recommended to use MAC address for any form of |
| user identification. As a result, as of Android M, local device MAC addresses |
| (for example, Wifi and Bluetooth) <em><strong>are not available via third party |
| APIs</strong></em>. The {@link android.net.wifi.WifiInfo#getMacAddress WifiInfo.getMacAddress()} |
| method and the {@link android.bluetooth.BluetoothAdapter#getAddress |
| BluetoothAdapter.getDefaultAdapter().getAddress()} method will |
| both return <code>02:00:00:00:00:00</code>.. |
| </p> |
| |
| <p> |
| Additionally, you must hold the following permissions to access MAC addresses |
| of nearby external devices available via Bluetooth and Wifi scans: |
| </p> |
| |
| <table> |
| <tr> |
| <th><strong>Method/Property</strong></td> |
| <th><strong>Permissions Required</strong></td> |
| </tr> |
| <tr> |
| <td> |
| <code><a href="{@docRoot}reference/android/net/wifi/WifiManager.html#getScanResults()">WifiManager.getScanResults()</a></code> |
| </td> |
| <td> |
| <code>ACCESS_FINE_LOCATION</code> or <code>ACCESS_COARSE_LOCATION</code> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <code><a href="{@docRoot}reference/android/bluetooth/BluetoothDevice.html#ACTION_FOUND">BluetoothDevice.ACTION_FOUND</a></code> |
| </td> |
| <td> |
| <code>ACCESS_FINE_LOCATION</code> or <code>ACCESS_COARSE_LOCATION</code> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <code><a href="{@docRoot}reference/android/bluetooth/le/BluetoothLeScanner.html#startScan(android.bluetooth.le.ScanCallback)">BluetoothLeScanner.startScan(ScanCallback)</a></code> |
| </td> |
| <td> |
| <code>ACCESS_FINE_LOCATION</code> or <code>ACCESS_COARSE_LOCATION</code> |
| </td> |
| </tr> |
| </table> |
| |
| |
| <h2 id="working_with_advertising_ids">Working with Advertising IDs</h2> |
| |
| <p> |
| Advertising ID is a user-resettable identifier and is appropriate for Ads |
| use-cases, but there are some key points to bear in mind when using it: |
| </p> |
| |
| <p> |
| <em><strong>Always respect the user’s intention in resetting the advertising |
| ID</strong></em>. Do not bridge user resets by using a more persistent device |
| identifier or fingerprint to link subsequent Advertising IDs together without |
| the user’s consent. The <a href= |
| "https://play.google.com/about/developer-content-policy.html">Google Play |
| Developer Content Policy</a> states: |
| </p> |
| |
| <div style="padding:.5em 2em;"> |
| <div style="border-left:4px solid #999;padding:0 1em;font-style:italic;"> |
| <p>...if reset, a new advertising |
| identifier must not be connected to a previous advertising identifier or data |
| derived from a previous advertising identifier without the explicit consent |
| of the user.</span></p> |
| </div> |
| </div> |
| |
| <p> |
| <em><strong>Always respect the associated Personalized Ads |
| flag</strong></em>. Advertising IDs are configurable in that users can limit |
| the amount of tracking associated with the ID. Always use the <code><a href= |
| "https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.Info.html#isLimitAdTrackingEnabled()"> |
| AdvertisingIdClient.Info.isLimitAdTrackingEnabled()</a></code> method to |
| ensure you are not circumventing your users' wishes. The <a href= |
| "https://play.google.com/about/developer-content-policy.html">Google Play |
| Developer Content Policy</a> states: |
| </p> |
| |
| |
| <div style="padding:.5em 2em;"> |
| <div style="border-left:4px solid #999;padding:0 1em;font-style:italic;"> |
| <p>...you must abide by a user’s ‘Opt out of interest-based advertising’ or 'Opt |
| out of Ads Personalization' setting. If a user has enabled this setting, you |
| may not use the advertising identifier for creating user profiles for |
| advertising purposes or for targeting users with personalized advertising. |
| Allowed activities include contextual advertising, frequency capping, |
| conversion tracking, reporting and security and fraud detection.</span></p> |
| </div> |
| </div> |
| |
| <p> |
| <em><strong>Be aware of any privacy or security policies associated with SDKs |
| you use that are related to Advertising ID use.</strong></em> For example, if |
| you are using the Google Analytics SDK |
| <code><a href= |
| "https://developers.google.com/android/reference/com/google/android/gms/analytics/Tracker.html#enableAdvertisingIdCollection(boolean)">mTracker.enableAdvertisingIdCollection(true)</a></code> |
| method, make sure to review and adhere to all applicable <a href= |
| "https://developers.google.com/analytics/devguides/collection/android/v4/policy"> |
| Analytics SDK policies</a>. |
| </p> |
| |
| <p> |
| Also, be aware that the <a href= |
| "https://play.google.com/about/developer-content-policy.html">Google Play |
| Developer Content Policy</a> requires that the Advertising ID “must not be |
| connected to personally-identifiable information or associated with any |
| persistent device identifier (for example: SSAID, MAC address, IMEI, etc.,) |
| without the explicit consent of the user.” |
| </p> |
| |
| <p> |
| As an example, suppose you want to collect information to populate database |
| tables with the following columns: |
| </p> |
| |
| <table> |
| <tr> |
| <td> |
| <table> |
| <tr> |
| <td class="tab2"> |
| <code>timestamp</code></td> |
| <td class="tab2"> |
| <code>ad_id</code></td> |
| <td> |
| <code><strong>account_id</strong></code></td> |
| <td class="tab2"> |
| <code>clickid</code></td> |
| </tr> |
| </table> |
| |
| <p>TABLE-01</p> |
| </td> |
| <td> |
| <table> |
| <tr> |
| <td> |
| <code><strong>account_id</strong></code></td> |
| <td class="tab2"> |
| <code>name</code></td> |
| <td class="tab2"> |
| <code>dob</code></td> |
| <td class="tab2"> |
| <code>country</code></td> |
| </tr> |
| </table> |
| <p>TABLE-02</p> |
| </td> |
| </tr> |
| </table> |
| |
| |
| <p> |
| In this example, the <code>ad_id</code> column could be joined to PII via the |
| <code>account_id</code> column in both tables, which would be a violation of |
| the <a href= |
| "https://play.google.com/about/developer-content-policy.html">Google Play |
| Developer Content Policy</a>, if you did not get explicit permission from |
| your users. |
| </p> |
| |
| <p> |
| Keep in mind that links between Advertiser ID and PII aren't always this |
| explicit. It's possible to have “quasi-identifiers” that appear in both PII |
| and Ad ID keyed tables, which also cause problems. For example, assume we |
| change TABLE-01 and TABLE-02 as follows: |
| </p> |
| |
| <table> |
| <tr> |
| <td><table> |
| <tr> |
| <td> |
| <code><strong>timestamp</strong></code></td> |
| <td class="tab2"> |
| <code>ad_id</code></td> |
| <td> |
| <code>clickid</code></td> |
| <td> |
| <code><strong>dev_model</strong></code></td> |
| </tr> |
| </table> |
| |
| </pre> |
| <p>TABLE-01</p> |
| </td> |
| <td> |
| <table> |
| <tr> |
| <td> |
| <code><strong>timestamp</strong></code></td> |
| <td class="tab2"> |
| <code>demo</code></td> |
| <td class="tab2"> |
| <code>account_id</code></td> |
| <td> |
| <code><strong>dev_model</strong></code></td> |
| <td class="tab2"> |
| <code>name</code></td> |
| </tr> |
| </table> |
| <p>TABLE-02</p> |
| </td> |
| </tr> |
| </table> |
| |
| |
| <p> |
| In this case, with sufficiently rare click events, it's still possible to |
| join between the Advertiser ID TABLE-01 and the PII contained in TABLE-2 |
| using the timestamp of the event and the device model. |
| </p> |
| |
| <p> |
| While it is often difficult to guarantee that no such quasi-identifiers exist |
| in a dataset, the most obvious join risks can be prevented by generalizing |
| unique data where possible. In the example, this would mean reducing the |
| accuracy of the timestamp so that multiple devices with the same model appear |
| for every timestamp. |
| </p> |
| |
| <p> |
| Other solutions include: |
| </p> |
| |
| <ul> |
| <li><em><strong>Not designing tables that explicitly link PII with Advertising |
| IDs</strong></em>. In the first example above this would mean not including the |
| account_id column in TABLE-01.</li> |
| |
| <li><em><strong>Segregating and monitoring access control lists for users or roles |
| that have access to both the Advertising ID keyed data and PII</strong></em>. If the |
| ability to access both sources simultaneously (for example, to perform |
| a join between two tables) is tightly controlled and audited, it reduces the |
| risk of association between the Advertising ID and PII. Generally speaking, |
| controlling access means: |
| |
| <ol> |
| <li> Keeping access control lists (ACLs) for Advertiser ID keyed data and PII disjoint to |
| minimize the number of individuals or roles that are in both ACLs, and</li> |
| <li> Implementing access logging and auditing to detect and manage any exceptions to |
| this rule.</li> |
| </ol> |
| </li> |
| </ul> |
| |
| <p> |
| For more information on working responsibly with Advertising IDs, please see |
| the <a href= |
| "https://support.google.com/googleplay/android-developer/answer/6048248?hl=en"> |
| Advertising ID</a> help center article. |
| </p> |
| |
| <h2 id="working_with_instance_ids_&_guids">Working with Instance IDs and GUIDs</h2> |
| |
| <p> |
| The most straightforward solution to identifying an application instance |
| running on a device is to use an Instance ID, and this is the recommended |
| solution in the majority of non-ads use-cases. Only the app instance for |
| which it was provisioned can access this identifier, and it's (relatively) |
| easily resettable because it only persists as long as the app is installed. |
| </p> |
| |
| <p> |
| As a result, Instance IDs provide better privacy properties compared to |
| non-resettable, device-scoped hardware IDs. They also come with a key-pair |
| for message signing (and similar actions) and are available on Android, iOS |
| and Chrome. Please see the <a href= |
| "https://developers.google.com/instance-id/">What is Instance ID?</a> help |
| center document for more information. |
| </p> |
| |
| <p> |
| In cases where an Instance ID isn't practical, custom globally unique IDs |
| (GUIDs) can also be used to uniquely identify an app instance. The simplest |
| way to do so is by generating your own GUID using the following code. |
| </p> |
| |
| <pre>String uniqueID = UUID.randomUUID().toString();</pre> |
| |
| <p> |
| Because the identifier is globally unique, it can be used to identify a |
| specific app instance. To avoid concerns related to linking the identifier |
| across applications, GUIDs should be stored in internal storage rather than |
| external (shared) storage. Please see <a href= |
| "{@docRoot}guide/topics/data/data-storage.html">Storage Options</a> guide for |
| more information. |
| </p> |
| |
| |
| <h2 id="understand_identifier_characteristics">Understanding Identifier Characteristics</h2> |
| |
| <p> |
| The Android Operating system offers a number of IDs with different behavior |
| characteristics and which ID you should use depends on how those following |
| characteristics work with your use-case. But these characteristics also come |
| with privacy implications so it's important to understand how these |
| characteristics play together. |
| </p> |
| |
| <h3 id="scope">Scope</h3> |
| |
| <p> |
| Identifier scope explains which systems can access the identifier. Android |
| identifier scope generally comes in three flavors: |
| </p> |
| |
| <ul> |
| <li> <em>Single app</em>. the ID is internal to the app and not accessible to other apps. |
| <li> <em>Group of apps</em> - the ID is accessible to a pre-defined group of related apps. |
| <li> <em>Device</em> - the ID is accessible to all apps installed on the device. |
| </ul> |
| |
| <p> |
| The wider the scope granted to an identifier, the greater the risk of it |
| being used for tracking purposes. Conversely, if an identifier can only be |
| accessed by a single app instance, it can’t be used to track a device across |
| transactions in different apps. |
| </p> |
| <h3 id="resettability_&_persistence">Resettability and persistence</h3> |
| |
| <p> |
| Resettability and persistence define the lifespan of the identifier and |
| explain how it can be reset. Common reset triggers are: in-app resets, resets |
| via System Settings, resets on launch, and resets on installation. Android |
| Identifiers can have varying lifespans, but the lifespan is usually related |
| to how the ID is reset: |
| </p> |
| <ul> |
| <li> <em>Session-only</em> - a new ID is used every time the user restarts the app. |
| <li> <em>Install-reset</em> - a new ID is used every time user uninstalls and reinstalls the app. |
| <li> <em>FDR-reset</em> - a new ID is used every time the user factory-resets the device. |
| <li> <em>FDR-persistent</em> - the ID survives factory reset. |
| </ul> |
| |
| <p> |
| Resettability gives users the ability to create a new ID that is |
| disassociated from any existing profile information. This is important |
| because the longer, and more reliably, an identifier persists (e.g. across |
| factory resets etc.), the greater the risk that the user may be subjected to |
| long-term tracking. If the identifier is reset upon app reinstall, this |
| reduces the persistence and provides a means for the ID to be reset, even if |
| there is no explicit user control to reset it from within the app or the |
| System Settings. |
| </p> |
| <h3 id="uniqueness">Uniqueness</h3> |
| |
| <p> |
| Uniqueness establishes the likelihood that identical identifiers exist within |
| the associated scope. At the highest level, a globally unique identifier will |
| never have a collision - even on other devices/apps. Otherwise, the level of |
| uniqueness depends on the size of the identifier and the source of randomness |
| used to create it. For example, the chance of a collision is much higher for |
| random identifiers seeded with the calendar date of installation (e.g., |
| 2015-01-05) than for identifiers seeded with the Unix timestamp of |
| installation (e.g., 1445530977). |
| </p> |
| |
| <p> |
| In general, user account identifiers can be considered unique (i.e., each |
| device/account combo has a unique ID). On the other hand, the less unique |
| an identifier is within a population (e.g. of devices), the greater the |
| privacy protection because it's less useful for tracking an individual user. |
| </p> |
| |
| <h3 id="integrity_protection_and_non-repudiability">Integrity protection and |
| non-repudiability</h3> |
| |
| <p> |
| An identifier that is difficult to spoof or replay can be used to prove that |
| the associated device or account has certain properties (e.g. it’s not a |
| virtual device used by a spammer). Difficult to spoof identifiers also |
| provide <em>non-repudiability</em>. If the device signs a message with a |
| secret key, it is difficult to claim someone else’s device sent the message. |
| Non-repudiability could be something a user wants (e.g. authenticating a |
| payment) or it could be an undesirable property (e.g. sending a message they |
| regret). |
| </p> |
| |
| |
| <h2 id="use_appropriate_identifiers">Common Use Cases and the Identifier to Use</h2> |
| |
| <p> |
| This section provides alternatives to using hardware IDs such as IMEI or |
| SSAID for the majority of use-cases. Relying on hardware IDs is discouraged |
| because the user cannot reset them and generally has limited control over |
| their collection. |
| </p> |
| |
| <h3 id="a_track_signed-out_user_preferences">Tracking signed-out user preferences</h3> |
| |
| <p> |
| <em>In this case, you are saving per-device state on the server side.</em> |
| </p> |
| |
| <p> |
| <strong>We Recommend</strong>: Instance ID or a GUID. |
| </p> |
| |
| <p> |
| <strong>Why this Recommendation?</strong> |
| </p> |
| |
| <p> |
| Persisting information through reinstalls is not recommended because users |
| may want to reset their preferences by reinstalling the app. |
| </p> |
| |
| <h3 id="b_track_signed-out_user_behavior">Tracking signed-out user behavior</h3> |
| |
| <p> |
| <em>In this case, you have created a profile of a user based on their |
| behavior across different apps/sessions on the same device.</em> |
| </p> |
| |
| <p> |
| <strong>We Recommend</strong>: Advertising ID. |
| </p> |
| |
| <p> |
| <strong>Why this Recommendation?</strong> |
| </p> |
| |
| <p> |
| Use of the Advertising ID is mandatory for Advertising use-cases per the |
| <a href="https://play.google.com/about/developer-content-policy.html">Google |
| Play Developer Content Policy</a> because the user can reset it. |
| </p> |
| |
| <h3 id="c_generate_signed-out_anonymous_user_analytics">Generating signed-out/anonymous user analytics</h3> |
| |
| <p> |
| <em>In this case, you are measuring usage statistics and analytics for |
| signed-out or anonymous users.</em> |
| </p> |
| |
| <p> |
| <strong>We Recommend</strong>: Instance ID; if an Instance ID is |
| insufficient, you can also use a GUID. |
| </p> |
| |
| <p> |
| <strong>Why this Recommendation?</strong> |
| </p> |
| |
| <p> |
| An Instance ID or a GUID is scoped to the app that creates it, which prevents |
| it from being used to track users across apps. It is also easily reset by |
| clearing app data or reinstalling the app. Creating Instance IDs and GUIDs is |
| straightforward: |
| </p> |
| |
| <ul> |
| <li> Creating an Instance ID: <code>String iid = InstanceID.getInstance(context).getId()</code> |
| <li> Creating a GUID: <code>String uniqueID = UUID.randomUUID().toString</code> |
| </ul> |
| |
| <p> |
| Be aware that if you have told the user that the data you are collecting is |
| anonymous, you should <em><strong>ensure you are not connecting the |
| identifier to PII</strong></em> or other identifiers that may be linked to |
| PII. |
| </p> |
| |
| <p> |
| You can also use Google Analytics for Mobile Apps, which offers a solution |
| for per-app analytics. |
| </p> |
| |
| <h3 id="d_track_signed-out_user_conversion">Tracking signed-out user conversion</h3> |
| |
| <p> |
| <em>In this case, you are tracking conversions to detect if your marketing |
| strategy was successful.</em> |
| </p> |
| |
| <p> |
| <strong>We Recommend</strong>: Advertising ID. |
| </p> |
| |
| <p> |
| <strong>Why this Recommendation?</strong> |
| </p> |
| |
| <p> |
| This is an ads-related use-case which may require an ID that is available |
| across different apps so using an Advertising ID is the most appropriate |
| solution. |
| </p> |
| |
| <h3 id="e_handle_multiple_installations">Handling multiple installations</h3> |
| |
| <p> |
| <em>In this case, you need to identify the correct instance of the app when |
| it's installed on multiple devices for the same user.</em> |
| </p> |
| |
| <p> |
| <strong>We Recommend</strong>: Instance ID or GUID. |
| </p> |
| |
| <p> |
| <strong>Why this Recommendation?</strong> |
| </p> |
| |
| <p> |
| Instance ID is designed explicitly for this purpose; its scope is limited to |
| the app so that it cannot be used to track users across different apps and it |
| is reset upon app reinstall. In the rare cases where an Instance ID is |
| insufficient, you can also use a GUID. |
| </p> |
| |
| <h3 id="f_anti-fraud_enforcing_free_content_limits_detecting_sybil_attacks">Anti-fraud: Enforcing free content limits / detecting Sybil attacks</h3> |
| |
| <p> |
| <em>In this case, you want to limit the number of free content (e.g. |
| articles) a user can see on a device.</em> |
| </p> |
| |
| <p> |
| <strong>We Recommend</strong>: Instance ID or GUID. |
| </p> |
| |
| <p> |
| <strong>Why this Recommendation?</strong> |
| </p> |
| |
| <p> |
| Using a GUID or Instance ID forces the user to reinstall the app in order to |
| overcome the content limits, which is a sufficient burden to deter most |
| people. If this is not sufficient protection, Android provides a |
| <a href="http://source.android.com/devices/drm.html">DRM API</a> |
| which can be used to limit access to content. |
| </p> |
| |
| <h3 id="g_manage_telephony_&_carrier_functionality">Managing telephony and carrier functionality</h3> |
| |
| <p> |
| <em>In this case, your app is interacting with the device's phone and texting |
| functionality.</em> |
| </p> |
| |
| <p> |
| <strong>We Recommend</strong>: IMEI, IMSI, and Line1 (requires <code>PHONE</code> |
| permission group in Android 6.0 (API level 23) and higher). |
| </p> |
| |
| <p> |
| <strong>Why this Recommendation?</strong> |
| </p> |
| |
| <p> |
| Leveraging hardware identifiers is acceptable if it is required for |
| telephony/carrier related functionality; for example, switching between |
| cellular carriers/SIM slots or delivering SMS messages over IP (for Line1) - |
| SIM-based user accounts. But it's important to note that in Android 6.0+ |
| these identifiers can only be used via a runtime permission and that users |
| may toggle off this permission so your app should handle these exceptions |
| gracefully. |
| </p> |
| |
| <h3 id="h_abuse_detection_identifying_bots_and_ddos_attacks">Abuse detection: |
| Identifying bots and DDoS attacks</h3> |
| |
| <p> |
| <em>In this case, you are trying to detect multiple fake devices attacking |
| your backend services.</em> |
| </p> |
| |
| <p> |
| <strong>We Recommend:</strong> The Safetynet API. |
| </p> |
| |
| <p> |
| <strong>Why this Recommendation?</strong> |
| </p> |
| |
| <p> |
| An identifier in isolation does little to indicate that a device is genuine. |
| You can verify that a request comes from a genuine Android device (as opposed |
| to an emulator or other code spoofing another device) using the Safetynet |
| API's <code>SafetyNet.SafetyNetApi.attest(mGoogleApiClient, nonce)</code> |
| method to verify the integrity of a device making a request. For more |
| detailed information, please see <a href= |
| "{@docRoot}training/safetynet/index.html">Safetynet's API documentation</a>. |
| </p> |
| |
| <h3 id="i_abuse_detection_detecting_high_value_stolen_credentials">Abuse detection: |
| Detecting high value stolen credentials</h3> |
| |
| <p> |
| <em>In this case, you are trying to detect if a single device is being used |
| multiple times with high-value, stolen credentials (e.g. to make fraudulent |
| payments).</em> |
| </p> |
| |
| <p> |
| <strong>We Recommend</strong>: IMEI/IMSI (requires <code>PHONE</code> |
| permission group in Android 6.0 (API level 23) and higher.) |
| </p> |
| |
| <p> |
| <strong>Why this Recommendation?</strong> |
| </p> |
| |
| <p> |
| With stolen credentials, devices can be used to monetize multiple high value |
| stolen credentials (such as tokenized credit cards). In these scenarios, |
| software IDs can be reset to avoid detection, so hardware identifiers may be |
| used. |
| </p> |