Exploiting Deep Links in Android - Part 4 (Mitigation)

When it comes to preventing Deep Link Hijacking, the message is simple: stop using Scheme URLs and start using (properly verified) App Links or Intent URLs.

[If you're lost maybe you should go back to Part 1]

As of August 2021 only about 6% of Android devices were still using Android 5 (Lollipop) or earlier versions of the OS, which don’t support App Links. So at this point, there are not a lot of excuses to still use Scheme URLs, which are insecure by design.

However, as discussed on Part 1, App Links can be tricky to verify correctly. Luckily, there are some tools that can help with this task.

Google provides a Deep Link Validator in their Ads platform as well as a Statement List Generator and Tester. This tools enables you to test if a given site domain grants app deep linking to the app with the specified name and SHA256 fingerprint:

I found this tool to be insufficient, and couldn't find any other tool that gave me all of the information I needed about an application's App Links.

As such, I ended up developing an open source tool that, among other things, can help you check if the App Links registered on the application are correctly verified:

~ python3 Android-Deep-Link-Analyser/deeplink_analyser.py \
-apk com.twitter.android.apk \
-p com.twitter.android \
-op verify-applinks

The output looks something like:

This tool has a lot of other features that might interested you.
Also, if you have any ideas, corrections or suggestions I would love to receive them on Github!


Validating Untrusted Data

As a general rule, you should treat all data received via deep link as being potentially malicious. As such, this data should be properly validated, sanitized and encoded.

If you remember, a lot of the vulnerabilities we explored on the previous posts could have been prevented if the developers checked a given URL against an allowlist.

However, when parsing and checking URLs we should keep in mind that a lot of popular URL parsers have known vulnerabilities:

Note that this issue is now fixed for API 28 - triggering a deep links with a malformed URL loads the attacker's scripts in Chrome rather than the app’s WebView - but this is still valid for older APIs.


WebView Hardening

As we saw on the previous posts, WebViews can potentially lead to local file exfiltration, they can allow a malicious user to access data created by other applications, and they're vulnerable to common web vulnerabilities.

So, when it comes to WebViews we should first ask ourselves: "could we replace it with a native Android UI component?"

If the answer is "Yes" we should go with the native approach.

If the answer is "No" we should enforce the following settings, unless absolutely necessary:

setJavaScriptEnabled(false);
setAllowFileAccess(false);
setAllowContentAccess(false);
setAllowFileAccessFromFileURLs(false);
setAllowUniversalAccessFromFileURLs(false);
setJavaScriptCanOpenWindowsAutomatically(false);
setMixedContentMode(1);

You should also be careful when using the following options:

setDomStorageEnabled
setCacheMode
setAppCacheEnabled + setAppCachePath
setGeolocationEnabled +setGeolocationDatabasePath

Note that these settings are safe by default on "modern" Android APIs, but you should verify if the app developer has not explicitly set an insecure configuration.

Finally, if your app directs users to URLs outside your domain, consider using Chrome Custom Tabs instead of a WebView:

CCT opens faster than a browser and, if preloaded via its warm-up call, is potentially even faster than a WebView. While it still runs Javascript, it is in its own process, which prevents apps from running malicious code. Furthermore, the CCT UI provides an action bar which shows the URL of the page being loaded, along with an SSL verification lock icon for secure pages.

Hopefully, you're now better equipped to protect your application.
On the next post we'll explore Testing methodologies.