In a previous article we saw how to protect API keys by using Mobile App Attestation and delegating the API requests to a Proxy. This blog post will cover the situation where you can’t delegate the API requests to the Proxy, but where you want to remove the API keys (secrets) from being hard-coded in your mobile app to mitigate against the use of static binary analysis and/or runtime instrumentation techniques to extract those secrets.
We will show how to have your secrets dynamically delivered to genuine and unmodified versions of your mobile app, that are not under attack, by using Mobile App Attestation to secure the just-in-time runtime secret delivery. We will demonstrate how to achieve this with the same Astropiks mobile app from the previous article. The app uses NASA's picture of the day API to retrieve images and descriptions, which requires a registered API key that will be initially hard-coded into the app.
The last section may have introduced some new technical terms to you, and so an overview of these is below.
This is the process of authenticating that a running instance of a mobile app is the same exact one that was uploaded to the app store. This process consists of attesting that the mobile app is not running in a compromised device, hasn’t been modified in any way, isn’t being manipulated during runtime, isn’t a target of an ongoing MitM attack, etc.
These are secrets provided to the mobile app at runtime via secure over-the-air updates from a third-party service, as they are required to make the API requests, and protected with Mobile App Attestation on retrieval and subsequent usage in the API calls.
Now let’s look at the app we are going to use to demonstrate these principles. It’s a very simple mobile app that uses the Nasa API to show some nice pictures in a list from which you can select any and see more details about it.
First, you need to clone the provided Github repo:
git clone –branch approov-runtime-secrets-protection https://github.com/approov/hands-on-api-proxy.git
Next, get your free NASA API key on this page. Once you get your API key you can add it to the src/client/android/local.properties file:
# While you are here add also:
Now, you need to open your Android Studio editor in the AstroPiks app folder at src/client/android and then build, install and run the mobile app on a real device or emulator. Then you should be presented with this screen:
If you are presented with any other screen then you may have missed one of the previous steps. For example, forgetting to update the API key in the local properties file would show you this screen:
A missing API key is not the only cause for this screen, you may also have a typo in the API key or in the API URL, or you may have network connectivity issues.
The API key was stored in the local.properties file and some developers may be happy with this approach because it's not hard-coded anymore in their code. However it should be noted that it is still present in the resulting binary as a string in the code, therefore it can be extracted via static binary analysis or via a Man in the Middle (MitM) attack.
To extract the API key via static binary analysis, many open source tools exist and one of the most popular ones is the Mobile Security Framework(MobSF). You can see it in action in this article How to Extract an API Key from a Mobile App by Static Binary Analysis:
All an attacker needs is to download the APK for the mobile app from the device and upload it to the MobSF dashboard. Wait for a short time to see it decompiled, and then just search for the API key string. If you want to follow the article and try it by yourself, it only takes a few minutes.
Alternatively, an attacker may choose a MitM approach in order to listen to the traffic between the mobile app and the API server and extract the secret and any other data that may be useful later to mount an attack.
Open Source tools exist to help with a MitM attack and one of the most popular ones is mitmproxy. You can see in action in this article How to MitM Attack the API of an Android App:
In the above image it is very easy to spot the API key used in the requests to the Nasa API. All an attacker needs now is to copy it to an automated script and make requests on your behalf. If this activity caused your Nasa API call quota to be exceeded, it would block you from using it, making your mobile app non-functional, and negatively impacting your users.
The Nasa API is free to use but how would the picture change if you were using a paid third-party API on your mobile app? Extraction and misuse of your 3rd party API key still has the risk of bringing down your mobile app of course, but in this case there is another scenario where the quota is not exceeded but rather significant unanticipated costs are incurred. In this situation, your customers may still be happy but your financial controller is definitely not!
Doing a MitM attack is a very interesting exercise that helps developers to better understand the mechanics involved. If you want you can follow the linked article instructions to setup the MitM attack and apply it to the AstroPiks app.
To do this you have two commands that are different from the linked article.
First, the path to the apk is different. You need to adjust it like this:
adb install src/client/android/app/build/intermediates/apk/debug/app-debug.apk
Second, the adb command to launch the app in the emulator is also different:
adb shell am start -n "com.criticalblue.android.astropiks/com.criticalblue.android.astropiks.PhotoGalleryActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
So far we have shown that it is relatively straightforward to extract an API key from an APK binary and of course the API key needs to be present there in order for the app to make the API requests, right? Well, this is what we are going to cover next. In fact, you don’t need to store it in the binary; instead you can have it securely delivered just-in-time using Runtime Secrets Protection.
We saw that secrets shipped inside mobile app binaries can be reverse engineered with static binary analysis or with a MitM attack at runtime. Clearly the best way to prevent this is to remove those valuable secrets from inside the binary of the mobile app and instead have them delivered just-in-time.
We will do this by using Mobile App Attestation to secure the AstroPiks app runtime secrets and all the HTTPS API requests with third-party APIs.
To achieve over-the-air secure updates we need to have a very high degree of confidence - at the time the secrets are dynamically retrieved - that the mobile app is not under any kind of attack and that it is a genuine and unmodified version of the one uploaded to the app store, and here is where the Approov Mobile App Attestation solution comes into play.
When the mobile app is launched an initial mobile app attestation is immediately launched via an SDK provided by Approov. This SDK will call the attestation service, resulting in some challenges for the app to execute and, depending on the results received, the attestation service will decide if it is trustworthy or untrustworthy. Once it is established that the mobile is not running on a compromised device (rooted, jail-broken, etc.), hasn’t been tampered with (re-signed, cloned, modified at runtime, etc.) and not actively under attack (MitM attack, Instrumentation Framework, etc), then it can receive over-the-air updates. This is the secure delivery method to provide the runtime secrets.
We will now show how to move from using static secrets to runtime secrets by modifying the Astropiks with just a few lines of code to integrate the Approov SDK to provide all the runtime secrets functionality and protection via Mobile App Attestation.
If you don’t have an Approov account, then you can start a trial (no credit card) in order to proceed with the hands-on exercise. Follow the instructions in the onboarding email to get ready to use the Approov service.
The commands you are about to execute require admin privileges, therefore you will need to switch from your developer role to an admin role.
First, open a terminal to be able use your Approov CLI, and start by enabling the admin role:
eval `approov role admin`
Now that your Approov CLI is ready you can start by enabling the managed trust roots.
When making API requests you need to protect the secrets in it from being extracted. Certificate pinning is normally the solution for this, but for third-party APIs you cannot pin against their certificates because you are not in control of when they will be rotated.
To solve this let’s enable managed trust roots for the Approov service and integrate it into the AstroPiks mobile app:
approov pin -setManagedTrustRoots on
This is necessary to block the use of self-signed certificates which are commonly used during a MitM attack, because now any request going through the Approov service will only be able to use official certificates, i.e. only ones issued by Certificate Authorities.
Next, we need to inform the Approov service about the API domain(s) we want to protect. These are the destinations of the API requests being made out of your mobile app. For AstroPiks it is api.nasa.gov:
approov api -add api.nasa.gov -noApproovToken
This completes the configuration for protecting the API calls to the Nasa API from MitM attacks. The Approov service doesn’t send Approov tokens because this is an API where you are not in control of the backend.
If you want to be able to see the Approov Service rejections in the logs of Android Studio, then you need to enable the policy to show the reason for the exception.
approov policy -setRejectionReasons on
First, we need to enable the Approov secure strings feature:
approov secstrings -setEnabled
Now, open the src/client/android/local.properties file and replace the value for the variable api.key with the placeholder nasa-api-key:
The nasa-api-key will be added later to the request URL as the exact same parameter as the real Nasa API key, because the Approov service (to be integrated in the next steps) will intercept the request and look for the query parameter &api_key=nasa-api-key in order to replace the nasa-api-key placeholder with the actual value of your Nasa API key.
So, let's set the placeholder and value for the runtime secret:
approov secstrings -addKey nasa-api-key -predefinedValue your-nasa-api-key-goes-here
Next, let’s integrate the Approov service and remove the secrets from the AstroPiks mobile app.
First, you need to start by adding the Approov service dependency to the AstroPiks app, and for that you need to open the file src/client/android/build.gradle and uncomment one line to enable jitpack in order to require the dependency from the Git repository on Github:
Next, open the file src/client/android/app/build.gradle and uncomment the last line to require the Approov service implementation:
Now, copy/paste from your onboarding email the Approov Config string, or alternatively use the Approov CLI to get it:
approov sdk -getConfigString
Then, open the src/client/android/local.properties file and add to it the Approov config string (Note that it is not a secret):
Even though the Approov config string is not a secret you shouldn’t commit it into your source code. That is why we are adding it here.
Now, go back to the file src/client/android/app/build.gradle and uncomment the line that loads it into the default config as a resource value:
Next, hit that button on Android Studio to synchronise Gradle, and if there are no errors you are ready to start using the Approov service in the AstroPiks mobile app.
To use Approov, open the src/client/android/app/src/main/java/com/criticalblue/android/astropiks/App.java class and uncomment just three lines of code to import and enable the Approov service and the use of the runtime secrets:
You also need to comment out the native OkHttpClient so that the one wrapped by Approov is used. That will handle the instantiation and use of the Approov SDK for you.
Click that button in Android Studio to build, install and run the AstroPiks mobile app in a real device, and you should get this screen:
If you look into the Android Studio logs you will see several entries like this:
This occurs because the Approov cloud service is not yet aware of the mobile app you are using, therefore you need to register it.
From the root of this repo execute:
approov registration -add src/client/android/app/build/intermediates/apk/debug/app-debug.apk
Before you restart the mobile app you need to wait around 30 seconds for the registration to propagate through the Approov cloud service infrastructure.
If, after restarting the mobile you still don’t see the Nasa pictures of the day and the logs still show app-not-registered, then your Android Studio is saving the APK in another location, therefore you need to register with this command:
approov registration -add src/client/android/app/build/outputs/apk/debug/app-debug.apk
Now, you should be able to restart the mobile app and then see the pictures of the day:
If you don’t see the pictures yet then you need to ensure you followed all the steps. I would advise starting by checking if the API key was replaced with the runtime secret placeholder in the local.properties file.
As you have been able to see, Approov Runtime Secrets Protection is very simple and fast to implement, and shouldn’t be that different in your own mobile app.
You should choose the Approov Runtime Secrets Protection when you wish to protect access to your own APIs as well as third-party APIs where you are not in control of the backend.
When you use Approov Runtime Secrets Protection you can remove all the secrets from your mobile app, preventing them being reverse engineered with static binary analysis or extracted with runtime attacks. These secrets or identifiers used to access other third-party APIs and services, for example API keys, access tokens, etc., will be provided via the Approov cloud service when your mobile app passes attestation, stopping them from being extracted and abused by attackers.
Approov Runtime Secrets Protection is a feature of the Approov Mobile App Protection solution, enabling you to fully protect your APIs and the third-party APIs you use from attack and abuse by bots, requests from cloned/fake apps, manual requests issued by attackers via cURL/Postman, etc.
Now that you know that hard-coded secrets are a thing of the past and that runtime secrets are available today you can take advantage of the Approov trial you set up during this hands-on exercise to prototype the removal of static secrets from your own mobile app.