Suppose I am developing a mobile application that makes calls to an API server. The API server is secured by an API Key.
I cannot hard-code the API Key inside the mobile application because it can be stolen.
How can I protect the API key?
How is that problem usually solved?</blockquote>
(It sounds like the API-key you are trying to protect is for an API service that you don't own.)
One approach is by using an authentication server. The private API-key is kept on the authentication server and only shared after a valid login.
So how does this work?<ul><li>User on the mobile client enters a login & password</li> <li>These credentials get sent to an authentication server where they are verified</li> <li>If the login is valid, the API-key is sent to the mobile client</li> </ul>
Architecturally, you would need a separate authentication server which would leave you with 2 different servers:<ol><li>
Some API-key server that you need a private API-key to use</li> <li>
Authentication server (used to verify user login and exchange private API-keys)</li> </ol>
A second approach is to use a pass through server. The private API-key is never shared in this approach. It is possible to add authentication onto the pass-thru server, but not required.
So how does this work?<ul><li>Mobile user contacts the pass-thru server for data from the API</li> <li>Pass-thru server makes the api call (with the stored private API-key)</li> <li>The API server responds with data to the pass-thru server</li> <li>Pass-thru server forwards the API response to the mobile app</li> </ul>
In this case, you own the pass-thru server so you never need to share your API keys and user authentication is optional.
Suppose I am developing a mobile application that makes calls to an API server. The API server is secured by an API Key.</blockquote>
Let's clear first a very common misconception among developers about APIs...THE DIFFERENCE BETWEEN WHO AND WHAT IS COMMUNICATING WITH YOUR API SERVER
To better understand the differences between the WHO and the WHAT are accessing your mobile app, let’s use this picture:
The Intended Communication Channel represents your mobile being used as you expected, by a legit user without any malicious intentions, using an untampered version of your mobile app, and communicating directly with your API server without being man in the middle attacked.
The actual channel may represent several different scenarios, like a legit user with malicious intentions that may be using a repackaged version of your mobile app, a hacker using the genuine version of you mobile app while man in the middle attacking it to understand how the communication between the mobile app and the API server is being done in order to be able to automate attacks against your API. Many other scenarios are possible, but we will not enumerate each one here.
I hope that by now you may already have a clue why the WHO and the WHAT are not the same, but if not it will become clear in a moment.
The WHO is the user of the mobile app that we can authenticate, authorize and identify in several ways, like using OpenID Connect or OAUTH2 flows.<blockquote>
Generally, OAuth provides to clients a "secure delegated access" to server resources on behalf of a resource owner. It specifies a process for resource owners to authorize third-party access to their server resources without sharing their credentials. Designed specifically to work with Hypertext Transfer Protocol (HTTP), OAuth essentially allows access tokens to be issued to third-party clients by an authorization server, with the approval of the resource owner. The third party then uses the access token to access the protected resources hosted by the resource server.
OpenID Connect 1.0 is a simple identity layer on top of the OAuth 2.0 protocol. It allows Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server, as well as to obtain basic profile information about the End-User in an interoperable and REST-like manner.</blockquote>
While user authentication may let your API server know WHO is using the API, it cannot guarantee that the requests have originated from WHAT you expect, your mobile app.
Now we need a way to identify WHAT is calling your API server, and here things become more tricky than most developers may think. The WHAT is the thing making the request to the API server. Is it really a genuine instance of your mobile app, or is a bot, an automated script or an attacker manually poking around your API server with a tool like Postman?
For your surprise you may end up discovering that It can be one of your legit users using a repackaged version of your mobile app or an automated script trying to gamify and take advantage of your service.
Well, to identify the WHAT, developers tend to resort to an API key that usually they hard-code in the code of their mobile app. Some developers go the extra mile and compute the key at run-time in the mobile app, thus it becomes a runtime secret as opposed to the former approach when a static secret is embedded in the code.
The above write-up was extracted from an article I wrote, entitled <em>WHY DOES YOUR MOBILE APP NEED AN API KEY?</em>, and that you can read in full here, that is the first article in a series of articles about API keys.<h2>YOUR PROBLEM</h2>
So your problem cannot be solved with an authentication/authorizaion server, no matter if it uses Oauth, OpenID or any other type of authentication, because as you may well understand by now, this server will identify only WHO is accessing your API server, not WHAT is accessing it.
Just to be clear I am not saying that this approach shouldn't be used, in fact using Oauth2/OpenID are the best approaches to identify the WHO is accessing the API server.
By now you may be thinking to yourself in how you gonna solve your issue:<blockquote>
I cannot hard-code the API Key inside the mobile application because it can be stolen.</blockquote>
Well you have bought yourself an headache, that no doctor or medicine can make it go away.
It's true that if you hide any secret in a mobile app, then it can then be reverse engineered. In this article I wrote about one of the most effective ways to hide an API key in a mobile app, by using JNI/NDK, but at same time I also wrote about how is possible to reverse engineer it:<blockquote>
It's time to look for a more advanced technique to hide the API key in a way that will be very hard to reverse engineer from the APK, and for this we will make use of native C++ code to store the API key, by leveraging the JNI interface which uses NDK under the hood.</blockquote>
Before I started responding to your question, I finished the draft for my next article, that will be about how to perform a Man in the Middle Attack to steal an API key, and you will be able to read on it something around this:<blockquote>
While we can use advanced techniques, like JNI/NDK, to hide the api key in the mobile app code it will not impede someone from performing a MITM attack in order to steal the api key. In fact a MITM attack is easy to the point that can even be achieved by non developers.</blockquote>
Am I telling you that no hope exists in protecting an API server from WHAT is accessing it? Well no I am not...<h2>POSSIBLE SOLUTION</h2> <blockquote>
How can I protect the API key?</blockquote>
A mobile app should only communicate with a API server that is under your control and any access to third part APIs services must be done by this same API server you control.
This way you limit the attack surface to only one place, where you will employ as many layers of defense as what you are protecting is worth.
Depending on the value behind the API key you are trying to protect, you may want to use a Web Application Firewall(WAF), and if you can afford it a User Behavior Analytics(UBA) solution.
WAF - Web Application Firewall:<blockquote>
A web application firewall (or WAF) filters, monitors, and blocks HTTP traffic to and from a web application. A WAF is differentiated from a regular firewall in that a WAF is able to filter the content of specific web applications while regular firewalls serve as a safety gate between servers. By inspecting HTTP traffic, it can prevent attacks stemming from web application security flaws, such as SQL injection, cross-site scripting (XSS), file inclusion, and security misconfigurations.</blockquote>
UBA - User Behavior Analytics:<blockquote>
User behavior analytics (UBA) as defined by Gartner is a cybersecurity process about detection of insider threats, targeted attacks, and financial fraud. UBA solutions look at patterns of human behavior, and then apply algorithms and statistical analysis to detect meaningful anomalies from those patterns—anomalies that indicate potential threats. Instead of tracking devices or security events, UBA tracks a system's users. Big data platforms like Apache Hadoop are increasing UBA functionality by allowing them to analyze petabytes worth of data to detect insider threats and advanced persistent threats.</blockquote>
All this solutions work based on a negative identification model, by other words they try their best to differentiate the bad from the good by identifying what is bad, not what is good, thus they are prone to false positives, despite of the advanced technology used by some of them, like machine learning and artificial intelligence.
So you may find yourself more often than not in having to relax how you block the access to the API server in order to not affect the good users. This also means that this solutions require constant monitoring to validate that the false positives are not blocking your legit users and that at same time they are properly keeping at bay the unauthorized ones.
Regarding APIs serving mobile apps a positive identification model can be used by using a Mobile App Attestation solution that guarantees to the API server that the requests can be trusted without the possibility of false positives.<h3>The Mobile App Attestation</h3>
The role of a Mobile App Attestation service is to guarantee at run-time that your mobile app was not tampered or is not running in a rooted device by running a SDK in the background that will communicate with a service running in the cloud to attest the integrity of the mobile app and device is running on.
On successful attestation of the mobile app integrity a short time lived JWT token is issued and signed with a secret that only the API server and the Mobile App Attestation service in the cloud are aware. In the case of failure on the mobile app attestation the JWT token is signed with a secret that the API server does not know.
Now the App must sent with every API call the JWT token in the headers of the request. This will allow the API server to only serve requests when it can verify the signature and expiration time in the JWT token and refuse them when it fails the verification.
Once the secret used by the Mobile App Attestation service is not known by the mobile app, is not possible to reverse engineer it at run-time even when the App is tampered, running in a rooted device or communicating over a connection that is being the target of a Man in the Middle Attack.
The Mobile App Attestation service already exists as a SAAS solution at Approov(I work here) that provides SDKs for several platforms, including iOS, Android, React Native and others. The integration will also need a small check in the API server code to verify the JWT token issued by the cloud service. This check is necessary for the API server to be able to decide what requests to serve and what ones to deny.CONCLUSION
In the end the solution to use in order to protect your API server must be chosen in accordance with the value of what you are trying to protect and the legal requirements for that type of data, like the GDPR regulations in Europe.
So using API keys may sound like locking the door of your home and leave the key under the mat, but not using them is liking leaving your car parked with the door closed, but the key in the ignition.
It is fair to say that any secret stored in a client app is vulnerable. Secrets stored in manifests or embedded in the code are quite easy to extract. Obfuscation and app hardening can make this more difficult. Storing secrets in secure files or keystores are better but still never completely secure. If the secret is valuable enough, it can be stolen.
An overview of mobile API security which starts with API keys and works through OAuth2 is at https://hackernoon.com/mobile-api-security-techniques-682a5da4fe10.
OAuth2 has multiple flows depending on your requirements. The most common flow, authorization code grant, uses both client auth (think API key) and user auth. If you only want client auth, you could use a simpler client credentials flow. AppAuth is an OAuth framework available for iOS and Android. I posted an Android walkthrough of AppAuth at https://hackernoon.com/adding-oauth2-to-mobile-android-and-ios-clients-using-the-appauth-sdk-f8562f90ecff.
For a walkthrough on how secrets can be compromised in an Android app, take a look at https://github.com/approov/shipfast-api-protection. And if you want to see how to remove secrets from your app altogether (requires 3rd party demo library), you can work through https://hackernoon.com/hands-on-mobile-api-security-get-rid-of-client-secrets-a79f111b6844.
Since you actually need the API Key to access the backend server, but cannot store the API key on the device, I can really only see one possible approach.
Build an intermediate Mobile API which in turn calls the Backend server API. Have your mobile application call the intermediate Mobile API. This Mobile API should only allow specific calls required for the mobile app, and only return the data needed by the mobile app.
To avoid exposing your intermediate Mobile API to any external party you should require some kind of authentication. Also, make sure that your intermediate Mobile API is served via https. To improve security further you could look into using certificates.
(You could encrypt your API key for the Backend API with a cryptographically strong algorithm and store on the device to avoid it being easily retrievable, but there are sniffing tools available that lets you sniff the traffic going out from a mobile device, even on https, so this is not a safe option.)