We're Hiring!

Hands on Mobile API Security - Using a Proxy to Protect API Keys

UGC 12591 The Fastest Rotating Galaxy Known

Editor's note: This post was originally published in May 2017 and has been revamped and updated for accuracy and comprehensiveness. The latest update was in September 2022.

API keys and other secrets poorly hidden inside mobile apps are a common source of mobile insecurity. You can do much better.

In this tutorial, you will work with a simple Android mobile app which uses an API key to access the NASA picture of the day service. An API Reverse Proxy introduced between your mobile app and the NASA picture service will remove the need for storing and protecting the API key on the mobile app itself. In addition to improved API security, this approach offers some benefits in manageability and scalability. Alternatively, you may choose the approach discussed in the Runtime Secrets Protection article which doesn’t require any API backend work to be done - a significant positive if you don’t have a backend team immediately available and need a solution ASAP. 

During the tutorial, you will modify an Android mobile app and a NodeJS API reverse proxy server. For demonstration purposes, both the Android mobile app and the API reverse proxy server can be run together on a single laptop, but to make it easier for you to follow along we will provide an online API Reverse Proxy server.

I assume that you have some very basic familiarity with Android and can read Java and Javascript. All code is provided, so it should be possible to follow along even if you have limited experience in these environments.

The AstroPiks Mobile App

The AstroPiks Android mobile app is relatively simple with only two main screens. The initial screen displays a gallery of recent NASA pictures of the day. Clicking on an image brings up a detailed screen containing the full image and its description.

AstroPiks mobile app screenshot     

The mobile app uses NASA's picture of the day API to retrieve images and descriptions. To access the service, the API requires a registered API key which will be initially stored in the mobile app.

Why Do We Need an API Reverse Proxy?

Mobile Apps of any complexity will make extensive use of multiple 3rd party services via their public APIs which means handling and safeguarding many secret API keys. Secrets are supposed to be kept secret. Unfortunately, for a secret held on a mobile app, it's not a question of if it will be stolen but when it will be stolen and how much effort it will take.

By introducing an API reverse proxy server between the mobile app and its 3rd party services, we can remove the API keys from an insecure mobile app and place them on a more secure API reverse proxy server. We’ll also add a mobile app attestation service to establish trust between the mobile app and the new API reverse proxy server. This approach is discussed in detail in the Mobile API Security articles.

We'll use the NASA service as an example of an API which would be typically called from a mobile app. We've added an extra hop between the mobile app and 3rd party service, but it does offer significant benefits. Since we've removed the secret from the mobile app, it's no longer there to be stolen.

If the secret is somehow compromised, it can be replaced in the API reverse proxy server with a fresh secret. From a manageability standpoint, since the secret is no longer on the mobile app, the decision can be made to improve security without requiring any change to the installed base of mobile apps.

The API reverse proxy server itself is stateless which brings load balancing, failure recovery, and other scalability benefits. By establishing trust between the mobile app and the API reverse proxy server, the mobile app attestation service offers a quick rejection filter to drop invalid traffic before burdening the actual API servers. These benefits increase as multiple API services are proxied through the same server.

Preliminary Setup

To get started, you need to download the tutorial source code, get some keys, and ensure your development tools are in place. The tutorial should run properly on windows, mac, or linux environments.

Android and NodeJS environments were chosen as sample demonstration environments. Other implementations, including iOS for the mobile app and NGINX or Go for the API reverse proxy, are also possible.

1. Git Clone the Tutorial Source Code

All tutorial source code is available on Github. In a terminal or command window, change to a directory where you will store the tutorial, and clone this public git repository:

git clone https://github.com/approov/hands-on-api-proxy.git

2. Register For an Api Key from Nasa (It's Free)

NASA requires a valid registration key to access their free pictures of the day service, and you can get your free NASA API Key on this page. Once you get your API key you need to add it to the .env file at the root of this repo, which doesn’t exist yet. Create one by duplicating the .env.example file to .env and then add your Nasa API Key:

NASA_API_KEY=___YOUR_API_KEY_HERE___

3. Android Studio

Ensure Android Studio and its tools are installed and reasonably up to date. Android Studio Chipmunk | 2021.2.1 was the one used during this tutorial. If you need a fresh install of the Android tools, go to the Android Developers Site to get started.

Initially the tutorial presumes you will be running the mobile app in an Android emulator, but you can also use an Android phone or tablet. The Android device should be running API 21 or higher.

4. Setup NodeJS

The NodeJS environment is used to build and run the example API reverse proxy server. We recommend you to use our online backend for the AstroPiks mobile app, that you can find at astropiks.demo.approov.io. If you prefer you can always run the API reverse proxy yourself via the docker stack on this repo or by using NodeJS installed on the host to run it, but bear in mind that the server must be available online to complete the last step in this hands-on exercise.

Docker Stack

A Docker stack for NodeJS is provided and wrapped with a bash script to make it easier to be used by developers not familiar with Docker, and you can see its help to find all the available commands:

./astropiks –help

If Docker is not your thing then you are free to not use it and just go with NodeJS installed directly on the host machine.

NodeJS on the host machine

Ensure the NodeJS environment is installed, preferably an LTS release from version 6 onward. If you need a fresh install, visit NodeJS to get started. Install the node version manager (nvm) if you want to maintain multiple node versions.

This will install NodeJS and its package manager, npm. We'll install additional package dependencies as we build the API reverse proxy.

When using NodeJS from your machine then you need to copy the .env file at the route of the repo to src/proxy/nodejs/src/.env.

Build the Initial AstroPiks App

The initial AstroPiks mobile app communicates directly with the NASA picture of the day service. The NASA API key must be stored in the mobile app and provided with each API call.

The AstroPiks mobile app is a fairly simple model-view-controller style master-detail photo gallery. The PhotoRequester class handles the initial API calls using the OkHttp library, and images are downloaded using the Picasso library. The App application class creates and provides the HTTP client and downloaders in a convenient place for all activities.

Fire up Android Studio and open the AstroPiks mobile app in the working directory at src/client/android. Android Studio will take a while to load library dependencies and rebuild the project. If your configuration is valid, the project should build without errors.

Before you install and run the Atropiks mobile app you need to add the Nasa API Key and URL to the src/client/android/local.properties file:

api.key=__YOUR_API_KEY_HERE__

# While you are here add also:
api.url=https://api.nasa.gov

Now, install and run the mobile app on a real device or emulator, and you should be presented with a screen similar to this one:

AstroPiks app home screenshot with a list of Nasa pictures

If you are presented with any other screen then you probably failed to follow one of the previous steps. For example, not updating the API Key in the local.properties file would show you this screen:

AstroPiks app home screenshot when fails to load a list of Nasa pictures

A missing API Key is not the only cause for this screen, you can also have a typo in the API Key or in the API URL, or you can be facing network connectivity issues. 

To debug connectivity issues you can open a browser or use cURL and try to access the NASA service, replacing NASA_API_KEY with your own key:

https://api.nasa.gov/planetary/apod?api_key=NASA_API_KEY&date=2022-07-08

For example, if you use the browser you should see this JSON response:

nasa api request example on the browser

Debug your mobile app connectivity setup and API key until you get a valid response like the one shown in the browser above. Ensure that your api.url and api.key are properly set in the local.properties file. 

Stealing a Client's API Keys

Your API key is used in API calls between the mobile app and the NASA server. Most production mobile apps will be calling multiple 3rd party APIs and will be holding multiple API keys.

Mobile applications should always use TLS best practices, including certificate pinning, to secure the API communications so that your API keys cannot be easily observed. As long as an API Key is used by the mobile  app, the APK contains a static representation of that key, therefore it can be reverse engineered with static binary analysis of the APK or via a MitM attack.

Via Static Binary Analysis

You can extract the API Key via static binary analysis and for that a plethora of open source tools exist, and one of the most popular ones is the Mobile Security Framework(MobSF), that you can see in action in this article How to Extract an API Key from a Mobile App by Static Binary Analysis:

screenshot from the mobile securirty framework dashboard

Obfuscation techniques can make this more difficult, but your keys will eventually be found, and if not via this method the attacker will do it via a MitM attack.

Via a MitM Attack

Several Open Source tools exist to help us with a MitM attack and one of the most popular ones is the mitmproxy, that you can see in use on this article How to MitM Attack the API of an Android App.

I challenge you to follow the article to replicate the steps to perform a MitM attack, and if you accept the challenge then you have two commands that are different from the linked article.

First, the path to the apk is different, therefore 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

If you follow all the steps successfully you will eventually arrive here:

screenshot from the mitmproxy cli and mobile app side by side

In the above image it is very easy to spot the API key used in the requests to the NASA API pictures of the day.

The Impact of a Stolen API Key

Once your API Key is discovered, it can be used to access NASA's public services. In this case, repeated calling of the NASA API by a hacker will trigger rate limits, and you will eventually be denied access as a result. But what if you are an e-commerce site? If your site is busy processing nonsense API calls, real customers will be denied access or give up because of poor responsiveness. A malicious hacker might be able to create a bunch of fake orders for merchandise or gain access to competitive information. Alternatively, a hacker could create a look-alike app using your API to display your inventory at a reduced site, gather orders from soon to be angry customers, and grab their credentials and credit card info in the process.

Let's get that secret out of your app.

Modify the AstroPiks Mobile App to Use the API Reverse Proxy

We saw that secrets shipped inside a mobile app APK can be reverse engineered with static binary analysis or with a MitM attack at runtime, and to solve this we will now see how we can remove the NASA API Key from being shipped inside the APK of the mobile app by delegating all the NASA API calls to an API reverse proxy.

Now, you need to edit the API Key and API URL on the src/client/android/local.properties file to look like this:

# The API key will no longer be compiled to the release binary (APK)
api.key=

api.url=https://astropiks.demo.approov.io/v1/api.nasa.gov

Next, rebuild, install, and run the modified AstroPiks mobile app on the Android emulator or device as before. You should see the same result as before, but now the photos are being served through the API reverse proxy. You should see the photo requests being sent to the API reverse proxy on the Android Studio logs, you just need to look for entries tagged with ASTROPIKS_APP.

If you do not see photos, double check the api.url in the local.properties file, the network connectivity, and try to copy/paste the URL from the Android Studio logs to a browser and check if it works.

If you have been paying attention, you noticed that the API reverse proxy is indeed open to the public, because no API Key is being used, remember you left it blank in the local.properties file. To fix this you can add an API Key for the API reverse proxy calls, but then the attacker can also extract it and continue to use the Nasa API through your API reverse proxy. Although, this time you have an advantage, you can rate-limit the API requests to the API reverse proxy and temporarily block the offender IP address, but an attacker can learn via trial and error how to stay under the rate-limit, thus effectively bypassing your counter-measures to keep him at bay. 

To effectively defend your API reverse proxy you need to have the ability to distinguish with a very high degree of confidence that what is doing the API request is indeed your original and unmodified mobile app and not an attacker, bots, or just someone curious poking around with your API via Postman or cURL requests, and in the next section you will learn how to do it.

Securing the API Reverse Proxy With a Mobile App Attestation Token

There is no longer any secret on the AstroPiks mobile app, but you have an API reverse proxy which can be used by anyone. You need a way to ensure that only trusted mobile apps can access your API reverse proxy server without requiring any new secrets on that mobile app. One way to do that is to use a dynamic Mobile App Attestation service to authenticate the mobile app as trustworthy to establish trust between the mobile app and the API reverse proxy server. 

We will now show how to modify the AstroPiks mobile app to work without static secrets while giving it the ability to prove to the API reverse proxy that it is the genuine and unmodified version that was uploaded to the official App store. You will be modifying the AstroPiks mobile app by changing just a few lines of code to integrate a third-party service SDK that will provide all the Mobile App Attestation service, and yes, the third-party service is us, Approov.

You will integrate the Approov Mobile App Attestation service by integrating the Approov SDK in the mobile app. Once the Approov SDK is running in the AstroPiks mobile app (next section), the SDK will attest it using the Approov cloud service. WIth each Mobile App Attestation, a short-lived JSON Web token (JWT) is returned representing the result of the Approov Mobile App Attestation by being signed with a shared secret for valid attestations and with an unknown secret for invalid attestations. The shared secret is only known by the Approov cloud service and by the API reverse proxy server, therefore it is never exposed to the mobile app. So, the JWT token needs to be added to the headers of each API request to be then validated by the API reverse proxy for a valid signature and expiration time. If valid, the API request can be fulfilled; otherwise a 400 response is returned.

AstroPiks Setup

The API reverse proxy endpoint for the the Approov Mobile App Attestation example will be v2, therefore you need to open again your local.properties file and update it to look like this:

api.url=https://astropiks.demo.approov.io/v2/api.nasa.gov

Now, if you launch the mobile app you will see that it fails to get the NASA pictures of the day, and this is because the API reverse proxy is not able to find the Approov token in the headers for the API request. We will fix it in the next section.

Adding the Approov Mobile App Attestation Service

If you don’t have an Approov account, then you should start a trial (no credit card) in order to be able to continue with the hands-on exercise. Follow the instructions in the onboarding email to get you ready to use the Approov Service.

Next, you will add the missing Approov Mobile App Attestation functionality into your mobile app by following the Approov Quickstart for OkHttp.

First, you need to add the Approov service dependency to the AstroPiks mobile app. Open the file src/client/android/build.gradle and uncomment the line to enable jitpack in order to require the dependency from the Github repository:

screenshot from the build.gradle file for the project

Next, open the file src/client/android/app/build.gradle and uncomment the last line to require the Approov service implementation:

screenshot from adding the Approov service dependency to the app build.gradle file.

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):

approov.config=#theapproovconfigstring=

Even though the Approov config string is not a secret, just an identifier, 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:

screenshot from getting the approov.config property from local.properties file in hte app build.gradle.

Next, 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, but don’t uncomment the line for the Approov 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.

When finished your App application class should look like this:

Hands on Proxy-Jul-21-2022-10-44-24-68-PM

The changes you made introduce the Approov service which under the hood uses the Approov SDK to create an Approov Mobile App Attestation object. This object will periodically ask the Approov Mobile App Attestation cloud service to verify its authenticity, and it will cache the resulting short-lived validation token. For API calls to the mobile app backend, an interceptor object is also added which will intercept all API requests and add the most recent Approov token to the request headers.

Testing the AstroPiks Integration with the Approov Mobile App Attestation Service

As you already learned the Approov service locks down your mobile app to your API server, therefore you should let the Approov Mobile App Attestation service know which API will the mobile app be making requests to:

approov api -add astropiks.demo.approov.io

 

This means that from now on you can only test that the Approov integration works as expected in your mobile app by using a real mobile device, and the mobile app needs to be making the API request to an online server for the API domain you added. During the development phase of your mobile app you can continue to use localhost API servers and emulators by configuring the Approov Mobile App Attestation service to always issue valid Approov tokens for a specific device. Learn more at Managing Devices.

Rebuild and run the AstroPiks mobile app in a real device. Sadly, the mobile app is still not showing photos! If it shows for you, then you forgot to update the api.url in the local.properties file to use the API v2 endpoint.

AstroPiks app home screenshot when failling to load a list of  Nasa pictures 2

If you have done everything correctly, the Approov service is now attesting the mobile app, but it is still returning a failed validation token. Until you register the mobile app with the Approov Mobile App Attestation service, the attestor has no idea how to validate your mobile app. This screen will also show if you run the mobile app in an emulator, because Approov rejects emulators by default.

If you look into the Android Studio logs you will see several entries with a 401 response code:

screenshot of Android Studio logs for the running app

Let’s register the mobile app APK with the Approov Mobile App Attestation service so that the attestor can attest the mobile app. 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 on your real device you need to wait around 30 seconds for the registration to propagate through the Approov cloud service infrastructure.

Now, restart your mobile app on a real device, and If after restarting it you still don’t see the NASA pictures of the day and the logs still show 400 response codes, then it’s possible your Android Studio may be saving the APK in another location, therefore try registering 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 on your real device and then see the pictures of the day:

AstroPiks app home screenshot with a list of  Nasa pictures 2

If you don’t see the pictures yet then you need to ensure you followed all the steps. Start by checking if the api.url and approov.config keys are correctly set in the local.properties file.

 

No Fake Mobile Apps

The secret is no longer in the mobile app. The API reverse proxy server holds the NASA API key. The Approov Mobile App Attestation cloud service and the API reverse proxy server share a secret to establish trust between the mobile app and the API reverse proxy server. Is it possible to build a fake app without the API key?

In Android Studio, try building a fake app by simply cleaning and rebuilding the existing app. Reinstall and run the freshly built app. Does it run successfully?

Even though it has exactly the same functionality, this is not the same APK build so the attestation fails. If you want to use this new app, you must separately register this new version. During your mobile app development workflow this may slow you down, thus we advise you to configure Approov to always issue a valid token for a specific device. Learn more about this in the Approov docs at Managing  Devices.

How is This Better Than Runtime Secrets Protection?

The AstroPiks mobile app is also used in the Runtime Secrets Protection article to show how to remove static secrets from the mobile app without the need for an API Reverse Proxy. Therefore you may ask yourself which approach you should use for your own mobile app.

The Runtime Secrets Protection makes it very easy to start removing static secrets from your mobile app without the need for any backend implementation at all. You just add the Approov SDK to secure your mobile app, allowing it to fetch the just-in-time secret to make the API request. The secret is only 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. 

If you already have an API backend for your mobile app then we recommend that you use it to delegate the requests for any 3rd party API you need to use from your mobile app. In other words, use the Runtime Secrets Protection when you don’t have control of the API backend your mobile app is talking with, for example a 3rd party API or an API provided by another part of your organisation.

Integrating Approov on your backend will allow for a tight security between your mobile app and the API backends it needs to communicate with, because now the backend has a very high degree of confidence that the API request is indeed from what it expects, a genuine and unmodified version of your mobile app, as uploaded to the app store. Any API request without a valid and not expired Approov token will be blocked, because it doesn’t come from your genuine mobile app - it may come from an ongoing MitM attack, a cloned or fake app, a bot, an attacker manually poking around with your API with cURL requests or with a tool like Postman, etc.

Conclusion

When secrets were held inside the mobile apps, replacing a compromised one required an update to the existing installed mobile apps on users’ devices. Now, since the API keys are no longer on the mobile app binary, they can be easily changed in the API reverse proxy server without requiring any change to your installed base of mobile apps.

Despite the extra hop, API reverse proxy servers offer enhanced security, scalability, and recovery benefits.

Try Approov For Free!

Cover image: UGC 12591: The Fastest Rotating Galaxy Known. Image Credit:NASA,ESAHubble

 

Skip Hovsmith

- Senior Consultant at Approov
Developer and Evangelist - Software Performance and API Security - Linux and Android Client and Microservice Platforms