The twisted world of Android Instance Identifiers and how to deal with it
The purpose of this article is to make you aware of the risks associated with improper usage of instance identifiers. There are many different use cases, but we will focus especially on instance identification of high-risk applications with the enrollment process.
TL;DR & Quick Recommendations
- Always use identifiers adequate to their purpose.
- Keep in mind that Google often changes its recommendations and drops support forvarious identifiers.
- For high risk applications, it is recommended to use a unique identifier independent from Android platform, for example UUID version 4.
- Follow the current good mobile application development practices -> see our “Guidelines on mobile application security Android edition”.
Mobile applications very often need to identify unique instances of an application installed on a specific device. A high risk application is the most typical situation where such identification is required, in order to provide two-factor authentication.
The modern approach to 2FA on mobile applications assumes that one of the authentication factors is knowledge of the password/PIN. The second factor is something that a user has, which typically is a particular mobile device. This mobile device needs to have a unique identifier, which is paired with the user id during the enrollment process.
SDK provided identifiers
In the old and shady Android days, it was quite popular to use one of hardware-related characteristics, like IMEI, MAC address or deviceId (usually a serial number).
Obviously, this approach is questionable from the security perspective, because each application installed on the device had access to those identifiers.
At some point, Google introduced a new identifier – androidId. The difference between androidId (Secure.Settings.ANDROID_ID – SSAID) and formerly used deviceId, whas that the first one was changed at each factory reset – it is not persistent. Also, since the Android 8 (Oreo), androidid identifier value was unique for each specific application, or rather the combination of an application name and a signing key. That means that androidid for applications A could not be accessed by application B.
What Google had introduced in 2018, Google took back in 2020. A new recommendation was to avoid hardware-based identifiers (bye, bye androidid). According to the documentation, androidid could be only obtained by applications with special carrier permissions or system applications with READ_PRIVILEGED_PHONE_STATE permission.
As a consequence, each application using androidId suddenly stopped working on devices with Android 10. By the way, examples of such applications are “IKO” – mobile banking of one of the biggest Polish banks and “mObywatel” delivered by Polish government and allowing citizen identification.
Another identifier provided by Google is advertisingId, but this one (as its name suggests) should be used solely for advertising purposes. It is not suitable for device identification because it can be manually resetted by the user.
Instance identification – how to do it right?
Keeping in mind the dynamics of changes in that regard, it is recommended not to not to rely on platform-based identifiers, but to generate identifiers on your own, using one of the secure libraries.
This approach would make you independent from Google, which in this case is a smart move. As presented before, Google changes its mind frequently on that matter and each change may cause a huge development impact on your side. By the way – this is what Google recommends now.
One of the best and most secure solutions is UUID in version 4 (Universally Unique IDentifier).
It is globally unique, secure, easy to use and google independent. Only thing to do is define identifier during enrollment process and store securely.
String uuid = UUID.randomUUID().toString(); editor.putString("app_identifier", uuid);
Below, example of UUID, androidID, instanceId (fireabaseId) and advertismentId stored in shared preferences:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?> <map> <string name="firebaseId">fUq13Zf5QZiG5S_zPuzB2z</string> <string name="advertisementId">ca-app-pub-3940256099942544/6300978111</string> <string name="uuid">b845d9a2-536a-4900-982c-8f8bb726ad5a</string> <string name="androidId">fc8fd5d216ebb394</string> </map>
Note that previous versions of UUID are obsolete and not considered secure, please avoid using them.
First of all, remember to use an identifier adequate to its purpose. For advertisement purposes use advertismentId. In case of instance identification for security sensitive applications, do not use hardware related identifiers, because it can compromise security.
Also avoid using Google provided identifiers because of frequent changes proposed by Google, which may result in incompatibilities with different Android versions. Use independent unique, like UUID, which ensures randomness, uniqueness and independence from Google.
Last but not least, remember to follow current good practices in the process of developing mobile applications. To make it easier, we had prepared a guide which gathers in one place the most significant challenges and suggests ways to solve them:
Feel free to reach me out. You can find me on Twitter or LinkedIn.
Head of Cloud Security