Introduction
On Android, the App Link system allows linking the content of websites to Android apps directly. Developers may define how a user can open certain websites within, say, an app that represents content on the web in a native mobile application.
Please note, there is a discrepancy between how the terms deep- and web link are defined in the context of Android compared to how they are used in the context of the world wide web.
=> Deep links Example: exampleapp://content/12345 |
=> Web links Example: http(s)://example.com/content/12345 |
=> Android App Links Example: http(s)://example.com/content/12345 Requirement: assetlinks.json must exists and be valid |
Figure 1: Examples of links on Android
First, we’d like to introduce the concept of deep links. Unlike deep links pointing to specific content on the world wide web, deep links in the context of mobile apps are formed by creating a specific uniform resource identifier (URI) linking to content within an app.
Deep link example: exampleapp://content/12345
The scheme, following the definition of an URI, here “exampleapp”, is used to denote the app to be opened on the mobile. Apps must be set up to handle given URIs of said scheme. On Android, developers must add an Intent filter [5] to their app’s manifest in order to handle deep links of a given scheme. It is important to note these may be defined using any scheme the developer chooses.
Web links consist of a typical uniform resource locator (URL). They feature either the HTTP or HTTPS scheme, followed by a host name, followed by a path. In the context of the world wide web these would usually be referred to as deep links but in the context of Android they are referred to as web links abiding by the Android documentation.
As URLs alone do not assert ownership of a host name, the Android App Link system has been established in order to allow the Android system to distinguish which apps may legitimately handle a given web link. A web link with appropriate proof of ownership is referred to as an Android App Link.
App Links are a specialized type of web links, which in turn are yet again a specialized form of deep links, as shown in Figure 1. Verification of an App Link is enabled by placing an assetlinks.json file on a publisher’s server to be available under the “.well-known” directory.
Example URL of an assetlinks.json file: https://www.example.com/.well-known/assetlinks.json
This file contains a package name and a SHA256 fingerprint of the app’s signing key, thereby allowing the Android system to verify if a given app is a valid target for opening a given App Link. Verification is performed by the Android system the first time a user attempts to open a link an app has registered. Without proof of ownership, the Android System will display a prompt, asking the user whether to open said link in a browser or in the given app. The autoVerify attribute allows skipping this prompt altogether if the Android system successfully verifies the mapping between the assetlinks.json and an installed app.
Issues
While the App Link system has been designed with security in mind, some issues have arisen over the years [1][2]. Most prominently, issues exist when redirecting from the browser to an associated app without said app being installed. The App Link system allows such links to be opened in a corresponding app without prior confirmation by the user, given a proper configuration. Under very specific circumstances, the invocation can be hijacked, redirecting the user to a malicious app (MA). In the following, three methods of invoking an App Link will be presented. These have been described in depth by Tang et al [1].
Setup and attacker model
The following issues were inspected on the five most recent versions of Android, as these cover most of the Android devices running today with a cumulative prevalence of 81,2% (Jan 6, 2023) [3]. Each release of a major Android version comes with a different number for its appropriate Android SDK API, referred to as the API Level.
Table 1 shows a mapping of Android releases and their corresponding API Level, as well as the codename of the respective release.
Android Version | API Level | Codename | ||
---|---|---|---|---|
Android 9 | API 28 | Pie | ||
Android 10 | API 29 | Quince Tart | ||
Android 11 | API 30 | Red Velvet Cake | ||
Android 12 | API 31 (and 32) | Snow Cone (v2) | ||
Android 13 | API 33 | Tiramisu |
All issues were tested using the official Android Emulator provided by the Android SDK. The official system images, also provided by the Android SDK, were used, all of which included the Google Play store- and services.
It is assumed the attacker cannot modify the system, furthermore the attacker cannot install apps featuring a package ID present in the Play Store.
The attacker can, however, install a malicious app. The attacker can install updates to that app in order to add further Intent-filters for the purpose of hijacking App Links from host names outside the attacker’s control.
The malicious app features a valid configuration of App Links under a host name controlled by the attacker. Furthermore, the configuration of the malicious app has been validated by the Android system before an additional Intent-filter is added by an update for malicious purposes.
Link hijacking
All three attack vectors revolve around the hijacking of links. The only difference lies in how a given link is invoked.
Let’s assume the legitimate app for handling the given App Link is not installed, instead a malicious phishing app is installed instead. The malicious app (MA) has its own App Links registered under a host name the attacker controls. Android’s verification of the assetlinks.json file therefore correctly maps the attacker-controlled host name to the MA.
Link click hijacking
This attack vector is based on a user clicking on a link in either the browser or a messaging app or anywhere else a clickable link may be shown on Android in order to open the appropriate app. The user would assume either the browser to open said link or the legitimate app to be opened.
Given the malicious app has registered Intent-filters for the host name of said link, the user will be redirected to the malicious app instead. Also, since the malicious Intent-filters were delivered by an update and the malicious app features an App Link configuration of its own which has already been validated, no prompt will be shown. The user will be redirected to the malicious app without confirmation.
This has been observed on Android versions up to but not including 12, as shown in Table 2. Installing the legitimate app to handle a given App Link mitigates this issue entirely.
Android Version | API Level | Malicious redirection w/o legitimate target app installed | Redirection w/ legitimate app installed | |
---|---|---|---|---|
Android 9 | API 28 | Yes | No | |
Android 10 | API 29 | Yes | No | |
Android 11 | API 30 | Yes | No | |
Android 12 | API 31 (and 32) | No | No | |
Android 13 | API 33 | No | No |
Link hijacking with Smart Text Selection (STS)
The second attack vector involves Smart Text Selection (STS). It is a feature introduced in Android 10 (API 29). It allows a user to select text and have Android suggest actions on that selection. This could be websites, documents or anywhere selectable text is shown.
These suggestions, among others such as copy/paste, also present apps, should an App Link be selected.
With the same setup as before, should a malicious app register Intent-filters of the given host name, the user will be shown an option to open the selected link in the malicious app. Given the App Link configuration has been validated, once again no prompt will be shown to the user.
This behavior has been observed on both Android 10 and 11. Android 9 did not yet feature STS and is therefore unaffected, as shown in Table 3.
Android Version | API Level | Malicious redirection w/o valid target app installed | Redirection w/ valid app installed | |
---|---|---|---|---|
Android 9 | API 28 | No (no STS) | No (no STS) | |
Android 10 | API 29 | Yes | No | |
Android 11 | API 30 | Yes | No | |
Android 12 | API 31 (and 32) | No | No | |
Android 13 | API 33 | No | No |
As shown in column four of Table 3, installing the legitimate app mitigates the issue entirely.
Instant app redirection
The third attack vector features the use of Instant Apps. These are a novel method of distributing Android apps without explicitly installing them. They allow opening apps to be run partially by the Android OS without specifically having to install a full app.
This attack, as described by Tang et al. [1], redirects users to the malicious Instant App (MIA) by giving the MIA a package name ranking higher in the lexicographical order, outranking the legitimate target app. For example, the package name “a.malicious.app” would rank higher than “com.example.legitimateapp”. Furthermore, the Android OS supposedly prefers Instant Apps over regular apps when determining an appropriate app to open a clicked link.
Similarly to the previous attack vectors, we were able to observe link hijacking only when the valid target app was not installed.
Installing the legitimate target app stopped link hijacking outright (see Table 4), regardless of running the malicious app as an Instant App with a shorter package name which supposedly was to outrank the legitimate, regularly installed app.
Also, unlike regular apps, initial successful verification of the App Link configuration does not have to occur.
Android Version | API Level | Malicious redirection w/o valid target app installed | Redirection w/ valid app installed (fully) | |
---|---|---|---|---|
Android 9 | API 28 | Yes | No | |
Android 10 | API 29 | Yes | No | |
Android 11 | API 30 | Yes | No | |
Android 12 | API 31 (and 32) | No | No | |
Android 13 | API 33 | No | No |
Conclusion & mitigation efforts
A lot has changed since these issues were initially discovered. Android 12 saw the introduction of an overhauled verification process for App Links within the Android system which allows for a more finely grained verification of App Links on a per-host-name basis.
The described link hijacking with all three attack vectors no longer works from Android 12 and up as the new App Link verification to have entirely mitigated these. Developers should be aware of the current state, especially on older devices.
Since the described hijacking from all three attack vectors mentioned above is mitigated by having the user install the legitimate target app, the risk lies in using App Links before ensuring the legitimate app for handling these is installed.
We would like to focus on a specific scenario requiring mitigation. If a developer were to choose an App Link in order to open the legitimate app, it may be tempting to also create a website under said link, prompting the user to install the legitimate app. The expected behavior would be to redirect the user to the legitimate app if it is installed or have the user shown the website, prompting to install the app. That scenario is prone to link hijacking using all three of the attack vectors mentioned above, that is, given the user is running an affected Android version shown in Table 1-4.
There are two mitigation options for that scenario we will discuss in the following:
Use the »Get Installed Related Apps API«
Since all three attack vectors are mitigated by installing the legitimate app, App Links shouldn’t be used unless the install state of the legitimate app can be determined.
Developers may use the »Get Installed Related Apps API« [4] on their website to check if the legitimate app is installed before offering an App Link for the user to open. It’s imperative you don’t offer any App Links before you have verified the legitimate target app is installed.
Use of Android Intent Links
Intent links for redirecting a user to an app do not suffer from attacks based on registering App Links maliciously. The only way of intercepting these would be by having the user install a malicious app featuring the same package name as the valid app. This, however, is less likely, as it may be assumed most users only use the Play Store to install applications and does not allow duplications of package names.
This approach can be combined with the use of the »Get Installed Related Apps API« in order to determine whether your app is installed, or links pointing to the Play Store should be shown.
Further mitigation options
Our conclusion draws a very specific scenario of how existing issues with App Links may be exploited. Other options of mitigation have been suggested such as disabling STS, these are, however, out of scope of the affected scenario described in our conclusion, we would therefore like to limit the discussion to the mitigation options available.
Sources
[1] Yutian Tang, Yulei Sui, Haoyu Wang, Xiapu Luo, Hao Zhou, and Zhou Xu. 2020. All your app links are belong to us: understanding the threats of instant apps based attacks. In Proceedings of the 28th ACM Joint Meeting on European Software Engineering Conference and Symposium on the Foundations of Software Engineering (ESEC/FSE 2020). Association for Computing Machinery, New York, NY, USA, 914–926. https://doi.org/10.1145/3368089.3409702
[2] Improving OAuth App-to-App Security, accessed 30.03.23, https://danielfett.de/2020/11/27/improving-app2app/#2-attacker-model
[3] Android Studio: Android Platform/API Version Distribution, updated Jan 6, 2023, accessed Mar 30, 2023
[4] Get Installed Related Apps API, Draft Community Group Report, 8 March 2021, URL: https://wicg.github.io/get-installed-related-apps/spec/ accessed Mar 1, 2023
[5] Intents and Intent Filters, Android Documentation, updated Mar 29, 2023, accessed Mar 29, 2023, URL: https://developer.android.com/guide/components/intents-filters
Author
Lawrence Dean
Lawrence Dean joined Fraunhofer AISEC as an IT security researcher in 2020, right after studying computer science at Technische Universität Darmstadt. His main topics of research involve mobile security, secure software engineering as well as digital identities with an added focus on hardware backed security.
Contact: lawrence.dean@aisec.fraunhofer.de