Securely Consume APIs on Mobile Devices – Part 1
Nowadays, most mobile applications use APIs to interact with backend services. And API providers must secure their APIs to protect business assets against information scraping, malicious activity, and denial of service attacks. Recent security breaches in REST APIs, which exposed sensitive data of million of users, shows how critical it is to properly secure APIs. In this context, mobile API consumption has been a challenge for mobile application developers. It requires that you have a lot of prerequisite knowledge and sufficient understanding for secure implementation.
This article is for any level of mobile developer, from beginner to advanced. If you are an experienced mobile developer who is already security savvy, feel free to jump to Part 2. Regardless of your experience, hopefully you will acquire some knowledge about securely consuming APIs in mobile apps.
- Part 1
We will briefly explain how to securely consume REST APIs in mobile devices. This includes basic techniques such as HTTP Basic Authentication, to advanced techniques such as mutual SSL, OAuth 2.0, and OpenID Connect 1.0. We will start with a simple example of API Key usage, then iteratively enhance its API protection.
- Part 2
We will explore how our Mobile SDK simplifies developer work by handling implementation details that can be quite complex if you’re writing your own API client.
Starting with HTTP Basic Authentication
To start, lets make sure that you understand the differences between Authentication and Authorization. The distinction between them is important in understanding how RESTful APIs works, and why connection attempts are either accepted or denied. Authentication is the validation of credentials in a connection attempt. This process consists of sending the credentials from the client to the API server using an authentication protocol. Authorization occurs after successful authentication; it verifies that the connection attempt is allowed. In simple words, Authentication verifies who you are, and Authorization verifies if you have access to a specific resource.
HTTP Basic Authentication is the most basic form of API authentication. The way it works is simple. As a developer, you register your application with the API provider and get an API Key (usually ID + Secret) to use when making API calls. The developer is responsible for storing this API Key in a secure place that no one else can access. In the app, each API call passes the API Key within the HTTP request to the API provider. Generally, base64 is preferred to encode the API Key and send it in the HTTP Authorization header with the word Basic, which is used by the API server to decode the authorization credentials. The API provider will extract from the API Key the ID and Secret, then validate these tokens before allowing the request to continue being processed.
This approach offers some basic protection. Any application making an API call will be rejected if the call does not contain a recognized ID (#1 in the picture above). The good thing is, it is pretty simple. A developer can get an API Key for an app and easily authenticate to the API service using this key. A bad thing is that you have to actually securely store the API key. There is no safely way to embed your API Keys into a mobile app that is distributed to many users. A mobile app with API Keys embedded inside of it, allows people to reverse engineer the app, grab those API Keys, and use it to make their own malicious API calls.
In addition, even though your credentials are encoded when you send them to the API provider in the request, they are not encrypted. It is very easy to retrieve the ID and Secret from a basic authentication. You should not use this authentication scheme on plain HTTP. Like all authentication protocols, HTTP Basic Authentication must be used over TLS/SSL at all times. Now, let’s talk about how to secure the communication channel and add another layer of security on the app.
Introducing Transport Level Security
Transport Layer Security (TLS) and its predecessor, Secure Sockets Layer (SSL), are cryptographic protocols commonly used to secure all communications between servers and clients, ensuring privacy, integrity, and authentication. To provide privacy, the connections between a client and a server uses cryptography to encrypt the data. The keys for this encryption are generated uniquely for each connection and are based on a shared secret negotiated at the start of the session (known as a TLS handshake). Authentication is provided using public-key cryptography to verify the identity of the communicating parties. The connection ensures integrity because each message that is transmitted includes a message integrity check using a Message Authentication Code (MAC) to prevent undetected loss or alteration of the data during transmission.
By default, the TLS proves only the identity of the server to the client using an X.509 certificate; authentication of the client to the server, is left to the application layer. With mutual TLS (mTLS), client and server exchange and verify each other’s public keys. Using certificate pinning, both client and server know which public keys to expect, so they compare the actual exchanged keys with the expected ones, rather than verifying through a hierarchical chain of certificates. The client and server must keep their own private keys secure. After the keys are verified, the client and server negotiate a shared secret, a MAC and encryption algorithms. Because it requires provisioning of the certificates to the clients and involves a less user-friendly experience, it is rarely used in end-user applications.
Looks good, right? So lets add the mutual TLS along with HTTP Basic Authentication on the app. Now, if we consider the app is running on your mobile device, the client traffic over TLS is reasonably safe from man in the middle attacks. But what if attackers installs your app on a device that they control? They could use a sniffer to observe the public key exchange, and use that knowledge to decrypt the channel and grab the API Key. They can now create their own malicious app, calling your API over a TLS channel. So even using a secured communication channel, you will need additional security to prevent APIs being called from unauthorized applications. Note, we also need to figure out how to properly secure our private key used for mTLS.
Enhancing HTTP Basic Authentication with HMAC
As discussed before, HTTP Basic Authentication requires that your raw API Keys (ID + Secret) is sent on every request.This increases the chance of exploitation because it does not safeguard against tampering of headers or body.
One way to improve this is to use Hash Message Authentication Code (HMAC). HMAC is a specific type of message authentication code. It can be used to simultaneously verify both the data integrity and the authentication of a message. In this approach, instead of sending both ID and Secret, only the ID of the API key is passed with each HTTP request. And the client computes a message MAC for each request using the Secret with an algorithm such as HMAC-SHA1 or HMAC SHA-256. As the Secret is known by both client and server, the server computes the received message MAC and compares it with the MAC sent in the request.
This way, the Secret is never present in the communication channel. Even if an attacker was listening to the conversation, they could not change the request and use the authentication information to properly sign it, as this would change the digest and the attacker does not have the Secret that both the server and client has. As it stands, an attacker can still deny or replay the request, but cannot alter it.
Now we have two secrets to keep safe in the client, the shared API secret and the client’s private key used for mTLS. Which brings us to next topic, secure secrets in mobile devices.
Secure Secrets in Mobile Devices
Poorly hidden API keys and secrets inside mobile apps, are a common source of security breaks. Often, developers will spend time trying to obfuscate secrets in the app, to authenticate their app to their server. Trying to obfuscate secrets in mobile apps is a futile effort as the secrets can always be recovered using the abundance of reverse-engineering and debugging tools available. Unfortunately, for a secret held on mobile apps, it is not a question of if secret can be stolen, but when, and with how much effort. So, where to store secrets?
Many mobile apps needs to handle passwords and others kinds of sensitive data, such as keys and login tokens. The Keychain Services for iOS and SharedPreferences for Android provides a secure way to store these items. Those are encrypted containers that securely stores sensitive data on behalf of apps in the users’ devices. You access those containers using the iOS and Android APIs.
Ok, so lets store our API Secret and TLS private key on this secure storage. Problem solved, right? No. You have the keys, but you do not have access to the user device. One way to do it would be on first launch of the app, call a endpoint over TLS in your API provider to download the credentials you need for the app. Then store those keys in the iOS or Android secured containers. This way the keys are not embedded in your code.
That’s it. We are good to go. Wait a minute… what if your application is installed on jailbroken device? A hacker will be able to get your keys from the Keychain. Ok, so for extra protection you could also keep the keys info in an encrypted format, but then you would need to embed decryption keys in your binary. This is how you end up down the rabbit-hole of the key exchange problem.
Don’t worry, we are getting there. Let me introduce two other concepts that will help you to improve the security of your app in the next section.
Overview of OAuth 2.0 and OpenID Connect
OAuth 2.0 and OpenID Connect (OIDC) are two complementary open standard protocols that are used to facilitate authentication (or authorization) to a mobile app and its associated API.
OAuth 2.0 is an open standard framework designed specifically to work with HTTP protocol. It essentially allows access tokens to be issued to third-party clients by an authorization server, with the approval of the resource owner without sharing their credentials. The client itself does not receive any information about the user, it just gets a token that it can pass along to the API. This mechanism is used by many companies such as Facebook, Google and Twitter to permit the users to share information about their accounts with third-party applications or websites.
OpenID Connect is an open standard authentication layer that sits on top of the OAuth 2.0 authorization framework. It includes an ID token which provides details around the identity and the authentication of that identity to the application. This allows an application to identify the user, the context of their authentication, and retrieve additional profile information about the identity.
Depending on the requirements of the application, one or both of these protocols can be put in use. For example, an application may not care about the identity of the user; if the app cares only that the user is authorized to make an API call, OAuth 2.0 may be sufficient. However, another application may want to know details about the authenticating identity so that it can render content in an appropriate language and welcome the user by name. This application may leverage OpenID Connect for that personalization.
Let’s discuss OAuth and OpenID Connect in more detail, and introduce some new concepts in Part 2.