• General
  • Device Fingerprinting Test Results, Concerns, and Questions

Skip to the end for the concerns and questions

Summary

Recently, I've been testing GrapheneOS device IDs and fingerprinting, particularly to determine the viability of running the same app on two separate profiles without the app provider knowing it's installed on the same phone Some examples: communication/VoIP apps where you don't want the VoIP provider to link your identity between the two numbers/accounts or Google apps where you know invasive fingerprinting may be a concern and don't want Google knowing Account A is on the same device as Account B.

The Test

For this test, I used a variety of device ID and fingerprinting apps, but it turned out that using only one was sufficient. The results you can see in the table below are from Fingerprint OSS Demo app - the same company made this that's behind the powerful https://fingerprint.com. Instead of posting the actual ID values, I replaced them with single-letter representations. All profiles are exactly identical aside from what is in the Setup column.
GS = Google Services; GP = Google Play Store app; Stable/Optimal/Unique = three different fingerprinting methods
GSF ID = Google Services Framework ID
I made two profiles each with GS and GP installed, one profile with just GS installed but not GP, and two profiles with neither GS or GP installed. I actually suspect that the fingerprinting app may be mislabeling the GSF ID and Android ID, but for this test, it's not particularly important if they named it right or not.

The Results

Results Table
The results displayed in the table show that the Stable and Optimal fingerprinting gave the same value across all profiles, but the Unique fingerprinting gave a different result based on the combination of GS and GP that was installed, but did give the same results otherwise. The so-called GSF ID and Android ID were different on all profiles, and the Android ID was not present unless GS was installed. The Media DRM ID (MediaDRM) was the exact same across all profiles and only changed if the whole device was factory reset.

This table provides information on which identifiers remain consistent across profiles and device actions (like factory reset) and is very useful for trying to understand the mitigations needed to prevent device identification (link: https://github.com/fingerprintjs/fingerprintjs-android/blob/main/docs/stability.md)

Concerns and Questions

This was a very limited test, but it still showed the limitations in preventing different apps, even those in separate profiles, from being able to uniquely identify the device they are on. This is concerning because if two different apps collude (e.g. if the owning company is the same or the companies share data) or if you have the exact same app installed on different profiles (e.g. Google Maps used for work locations on a "work" profile and Google Maps used for personal locations on a "personal" profile), this enables your identity to be easily linked even across totally separate profiles.

Below is just a sampling of the data available to an app with no extra permissions that were used to fingerprint:
Media DRM ID
Applications List
System Applications List
Screen Off Timeout
Font Scale
End Button Behavior
Time Zone
Battery Health
Battery Full Capacity
PIN/Fingerprint Status
...and more - a complete list of data points is provided in the app

  1. Why does every single app needs to have access to the MediaDRM since it is a static, unique identifier? It's as bad as giving access to the IMEI minus the factor reset capability.
  2. Is it possible for GrapheneOS to generate a unique MediaDRM value for each profile?
  3. Is it possible to spoof device fingerprinting data points such as the battery capacity, PIN status, time zone, etc. unless the user agrees to allow apps to access this treasure trove?
  4. The main question: In your opinion, what is the viability of having the same (non-privacy-respecting) app installed on two separate profiles and preventing it from determining they are both on the same device? Are there any particular steps to take to achieve this?

    Does this mean that the application list is visible across profiles? For example an app in a secondary profile can view what apps are installed in the main profile?

      rigor-us

      In your opinion, what is the viability of having the same (non-privacy-respecting) app installed on two separate profiles and preventing it from determining they are both on the same device?

      I don't think it is viable. The level of invasive hardware access restrictions, functionality crippling, virtualisation-based control etc. you would need to implement would be probably be a whole new research and operating system project on its own.

        Pacienco You're probably right. I think it would go a long way just to solve the MediaDRM ID issue. This wouldn't solve advanced fingerprinting attempts, but most apps still try to separate users by finding individual unique identifiers or by storing a value somewhere. The MediaDRM value makes device identification extremely simple and reliable for all apps, even if they don't try to fingerprint.

        Is there any reason why GrapheneOS can't restrict this or change it per profile or spoof it or something?

          16 days later
          4 days later

          rigor-us The MediaDRM value makes device identification extremely simple and reliable for all apps, even if they don't try to fingerprint.

          I just came across this:

          Changes to Device Identifiers in Android O (April 2017l

          Widevine ID

          For new devices shipping with O, the Widevine Client ID returns a different value for each app package name and web origin (for web browser apps).

          That suggests that, while a single fingerprint web site might get the same DRM i.d. for Vanadium in different user profiles on the same device, a different web site might get a different i.d. for Vanadium across profiles on that same device. Leaking to one app or site that two "users" are on the same device might be unwanted, but it wouldn't be as bad as leaking across sites.

          Checking this would involve some experimentation.

            de0u

            Thank you for filing that issue on GitHub. I think restricting app access to the DRM ID would solve this issue, so hopefully it gets picked up.

            Also great Widevine ID info. Unfortunately, it only seems to apply to web browsers and not non-browser applications, but it is a good piece of information to know to help mitigate tracking.

            If you hear anything else about these IDs getting restricted or optionally blocked in GrapheneOS, maybe you could post here to keep this thread up-to-date. Fingers crossed this gets some solutions since currently it's essentially impossible to prevent apps from tracking you across different profiles, packages, etc. Thanks again.

              rigor-us Also great Widevine ID info. Unfortunately, it only seems to apply to web browsers and not non-browser applications, but it is a good piece of information to know to help mitigate tracking.

              The text I quoted includes "the Widevine Client ID returns a different value for each app package name and web origin (for web browser apps)". The "web origin" part is in an "and" clause. So I think that text is intended to be decoded as covering both non-browser applications and web sites in browsers.

              To determine the current severity of the issue, it would probably be productive to experiment with this, and/or to read a bunch of code.

              Ah thank you for fixing my misread of that. That's slightly better, but really, a primary use for different profiles is when you need the same app "twice." Let's say I need Application X for a private use and Application X for a public use. In such a case, most users in this situation would not want Application X to have such a simple way to determine they are on the same device. Of course, it's still nice that Application X and Application Y would get different IDs (supposedly), but this still misses a common use-case for profiles, I think, so I believe your issue on GitHub is still relevant and important.

              • de0u replied to this.

                rigor-us That's slightly better, but really, a primary use for different profiles is when you need the same app "twice." Let's say I need Application X for a private use and Application X for a public use. In such a case, most users in this situation would not want Application X to have such a simple way to determine they are on the same device.

                Indeed. But when it comes to DRM for copy-protected media, the people who play that game actively don't want one device to be able to appear as two devices. For example, if they have a free trial period, they don't want people to be able to get an infinite stream of free trials by just creating new user profiles on one device. Reading between the lines, it appears that Google and media companies made a compromise, that a factory reset causes a device to become "fresh", but that less-annoying things cause the device to retain a single identity per media provider.

                If an app (or web site) that is not providing copy-protected media is inquiring about Media DRM i.d.'s, that would presumably be for illicit fingerprinting. If GrapheneOS were to alert the user, that might be useful; if it were configurable to reject requests, that might also be useful. Luckily the existing "grant/deny/allow-once" infrastructure seems applicable.

                Absolutely seems to be the case. Grant/Deny/Allow is the best solution because it makes all parties happy. That way, apps for which DRM is relevant can still be optionally granted access to this unchanging ID, which doesn't compromise their ability to use the ID as intended, but it still protects us against any app using it just for fingerprinting.

                Has anyone been able to validate that mediadrm can be reset on any device?

                My testing on a p6a have found that mediadrmID reported by Fingerprint OSS app have persisted throughout factory reset, reflash graphene and reflash stock OS.

                I suppose it is possible that any reset requires an online "provisioning" when using drm, but I do not know how to investigate that possibility further. I question if this identifier can be reset at all which would be very worrisome as this could bypass much of the fingerprinting protection and isolation claimed by stock android and by graphene, including for wifi-only devices.

                • de0u replied to this.

                  HaveDoubts That is concerning.
                  Do you have a relationship with any DRM companies, e.g., Netflix? Could it be that you sign in to them and they re-provision you the old way?

                    de0u Unfortunately I am unable to test this at currently, but I welcome the results of anyone who can!

                    I have found some additional posts indicating that malicious app developers are using this workaround for persistent device tracking:

                    https://stackoverflow.com/questions/58103580/android-10-imei-no-longer-available-on-api-29-looking-for-alternatives

                    https://stackoverflow.com/questions/64509905/how-to-get-unique-id-in-android-q-that-must-be-same-while-uninstalling-and-inst

                    It would be great to hear thoughts from the graphene devs or anyone with more android experience, it appears this tracker was actively or negligently left exposed by google when they restricted access to other identifiers.

                    I definetely support limiting access through grant/deny/only-once to help towards closing this tracking loophole, but also would like to understand if it can be reset given its trivial current and historical access...

                    a month later

                    @HaveDoubts There's no claimed protection against fingerprinting by native apps by Android or GrapheneOS. Our FAQ on non-hardware identifiers explains how fingerprinting is possible. None of this is a bypass for any kind of isolation. Web sites can successfully do fingerprinting in many ways in a far more restricted/limited environment. Even the most strict anti-fingerprinting features deployed for web browsers don't prevent doing it via JavaScript-based timing measurements to measure performance along with other side channels. Native apps are inherently able to fingerprint in many different ways and it's unrealistic to bring it to the same level as web pages without running apps in a standardized virtual machine with more limited functionality than they currently have available. There has only recently started being any significant progress on mitigating fingerprinting for the web and the same thing has barely begun for native app environments. The difference in the starting points is also significant. For example, access to information about battery life is relatively new in web browsers and there's limited list of similar APIs but access to far more than that has always been available to native apps.

                    https://grapheneos.org/faq#hardware-identifiers
                    https://grapheneos.org/faq#non-hardware-identifiers

                    Examples of the global OS configuration available to apps are time zone, network country code and other similar global settings. Per-profile examples are dark mode and language. Similar to extension and browser configuration / state being fingerprinted by web sites, an app could use a combination of these things in an attempt to identify the installation. All of these things vary at runtime and can be changed, but some are fairly unlikely to change in practice after the initial setup of the device such as the ones listed above. GrapheneOS will likely add further restrictions in this area and a couple toggles for certain cases like time zones to use a standard value instead.

                    The known flaw of the Media DRM ID not having profile support is being worked on both upstream and in GrapheneOS. The current implementation is a per-app ID rather than a per-app-per-profile ID as it should have been. You should test in 2 apps with different app ids in addition to testing with an app with the same app id in 2 different profiles. There are other flaws with how this feature is implemented and the approach we're considering is gating it behind a permission toggle because changing how it works will cause breakage while returning a placeholder value with a toggle for returning the real value will provide a way for users to still use apps using this as part of a media DRM implementation. Addressing this will not be very useful due to other ways of doing fingerprinting and therefore it hasn't been one of our priorities since it will only improve privacy against apps specifically exploiting this vulnerability as opposed to fingerprinting which cannot really be significantly mitigated without virtualization.

                    rigor-us Apps can only see the list of apps within the same profile and it's not a very stable identifier. There's a per-app-per-profile software identifier (ANDROID_ID) so identifying a specific profile doesn't require apps to do fingerprinting.

                    Media DRM ID is known to be flawed and that's why we're planning on gating it behind a toggle for returning a placeholder value. It hasn't been implemented yet because it won't resolve the broader issue of fingerprinting so it's not one of the highest priorities. It's going to get addressed in GrapheneOS but it isn't going to change much.

                    In the much longer term, support for running apps in virtual machines is planned. There will be a much more limited set of functionality available which will gradually need to be filled in and there can be far more toggles. This is the only way of hiding many things like the device model from apps by having the same virtual machine image builds across devices and supporting using a standardized screen resolution, etc. They could still do timing/performance-based fingerprinting which is also doable by websites. This can also theoretically be used for communication between apps and even web sites. The performance impact of CPU and other resource usage by an app or web site can be observed by others, so there's inherently a potential for data leaks and communication through this approach, not only fingerprinting the hardware and OS based on performance of various functionality.

                    We do not think fixing the Media DRM ID is realistic but rather we'll need to provide a toggle where a placeholder value such as one based on ANDROID_ID can be returned by default with a notification provided to the user informing them the app tried to access it and that they can toggle on using the actual Media DRM ID if they want to do that. Trying to fix it would likely break the functionality since it wouldn't be the expected value anymore. This feature predates the removal of access to actual hardware identifiers and they did seem to take privacy into account by making it per-app but didn't make it per-profile-per-app as required to properly support profiles. It may not provide the intended functionality with a per-profile-per-app approach.

                    Android trying to prevent apps identifying the device is still really in an early phase and Android removing the most obvious way of doing it (hardware identifiers) doesn't mean that it has been prevented. Not being able to access hardware identifiers like IMEI is still very useful, especially if all other identifiers beyond device model and OS can be reset or changed.

                    2 years later

                    I recently did some testing of RDM ID identifiers, using the two software mentioned at https://discuss.grapheneos.org/d/19484-unique-drm-id/7 .

                    The result was that for the same software Stock OS, Stock OS with factory settings restored, GrapheneOS, and GrapheneOS with factory settings restored the RDM ID was an identical value.

                    I don't know if there is any way to change the value of RDM ID.

                    I've used a near real name google account to log into sandboxed Play services, and if it sends the RDM ID to google then the google account in my other profiles is no longer anonymous. And there is no way to restore my anonymity on this device by restoring factory settings.