I'm a bit disappointed about ProGuard.
I am using Gradle to hide my Google MAP API KEYS. I also read this question here Manage Google Maps API Key with Gradle in Android Studio
and did the same. If you follow the accepted answer in this question, your api key won't get obfuscated by ProGuard. The question is why?
There are two good answers. One with ManifestPlaceHolder, one with using #string
Still, if I decompile my app, there is still my weather api key to seen.
I am using private String myweatherapikey = BuildConfig.MY_API_WEATHER_KEY; and it is amazing (in a bad way) how ProGuard DOES NOT obfuscate this, even when using Gradle.
When you do reverse engineering it looks like private String myweatherapikey ="MY KEY IN PLAIN TEXT";
I am trying to obfuscate my keys since days but nothing worked, even using Gradle.
How do you hide your keys ? It really annoys me that all my keys are public, when you decompile my app.
Second question: I think it is impossible to hide your google maps api key. There are 2 keys, one for release-version and one for debug-version. Both of them are stored in src/debug and src/release. You can't hide this, right?
OBFUSCATION
your api key won't get obfuscated by ProGuard
If Proguard or any other tool obfuscates the API key, then it also needs to be de-obfuscated at run-time, otherwise you cannot use it.
No matter if you have an obfuscation mechanism or even an encryption mechanism, an attacker just needs to hook during run-time an instrumentation framework, like Frida, to the code that returns the API after it have been de-obfuscated or decrypted.
Frida:
Inject your own scripts into black box processes. Hook any function, spy on crypto APIs or trace private application code, no source code needed. Edit, hit save, and instantly see the results. All without compilation steps or program restarts.
Another approach for the attacker is to perform a MitM attack in a device he controls or was able to compromise, and intercept all requests between the mobile app and the backend in order to extract the API key from the header, and you can read my article Steal that API Key with a Man in the Midlle Attack to learn how it can be done:
So, in this article you will learn how to setup and run a MitM attack to intercept https traffic in a mobile device under your control, so that you can steal the API key. Finally, you will see at a high level how MitM attacks can be mitigated.
YES, IT'S PUBLIC
I am trying to obfuscate my keys since days but nothing worked, even using Gradle. How do you hide your keys ? It really annoys me that all my keys are public, when you decompile my app.
From the moment you publish a mobile app into the Google, Apple store or any other store, the binaries can be downloaded and reverse engineered, therefore anything inside of them must be considered to be in the public domain, be it secrets or just code.
Techniques to Hide API Keys and to Reverse Engineer them
My favorite tool to reverse engineer a binary of a mobile app is the MobSF:
Mobile Security Framework (MobSF) is an automated, all-in-one mobile application (Android/iOS/Windows) pen-testing, malware analysis and security assessment framework capable of performing static and dynamic analysis.
You can read my article How to Extract an API key from a Mobile App with Static Binary Analysis to understand how this is done and at same time to learn the several techniques used to try to hide an API key, and see how they are easily bypassed:
During this article we will use the Android Hide Secrets research repository that is a dummy mobile app with API keys hidden using several different techniques.
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.
GOOGLE MAPS API KEY
Second question: I think it is impossible to hide your google maps api key. There are 2 keys, one for release-version and one for debug-version. Both of them are stored in src/debug and src/release. You can't hide this, right?
If you have read all the links I posted above, then by now you may already have realized that is indeed a Mission Impossible to hide any secret in the binary of your mobile app.
The bottom line is that if is in the binary it can be extracted by static analysis or during run-time.
I am not really familiar with the Google Maps usage in a mobile app, therefore I don't know if its possible to move the calls for it to the backend, because this is what it must be done with any usage of Third Party APIs in a mobile app, otherwise the API key is vulnerable to be extracted and abused, and if you are billed or rate limited based on it, then you may be in trouble when an attacker get hands on your API key.
THIRD PARTY APIS
Currently you are usage of Third Party APIs puts your mobile app in this position:
But preferentially your mobile app should be in this position:
While in the graphics I mention a Reverse Proxy, it could be the backend for your mobile app.
NOTE: The graphics belong to an article that I am currently writing about the use of a Reverse Proxy to access Third Party APIs.
Securing the API keys to access Third Party APIs is much easier when delegating access to them to a reverse proxy or backend we are in control of, and an immediate advantage of this approach is that the API keys for the Thrid Party services are not anymore in the public domain, aka the binary of your mobile app.
So from the graphics we are left with only one API key to secure, the one to access your reverse proxy or backend, where you can employ as many security measures as you can afford to prevent unauthorized access to it.
POSSIBLE SOLUTION
How do you hide your keys ?
Would not be better to not have any keys at all to hide in your mobile app, because that would be the ideal solution. So the above graphic would look more like:
To be in a position where you don't need to ship any secrets in your mobile app you need to resort to the Mobile App Attestation concept, and from this article section I will extract the relevant bits, that explain it's role:
Before we dive into the role of a Mobile App Attestation service, we first need to understand the difference between what and who is accessing the API server. This is discussed in more detail in this article, where we can read:
The what is the thing making the request to the API server. Is it really a genuine instance of your mobile app, or is it a bot, an automated script or an attacker manually poking around your API server with a tool like Postman?
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.
The role of a Mobile App Attestation service is to authenticate what is sending the requests, thus only responding to requests coming from genuine mobile app instances and rejecting all other requests from unauthorized sources.
In order to know what is sending the requests to the API server, a Mobile App Attestation service, at run-time, will identify with high confidence that your mobile app is present, has not been tampered/repackaged, is not running in a rooted device, has not been hooked into by an instrumentation framework(Frida, xPosed, Cydia, etc.), and is not the object of a Man in the Middle Attack (MitM). This is achieved by running an SDK in the background that will communicate with a service running in the cloud to attest the integrity of the mobile app and device it is running on.
On a 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 know. In the case that attestation fails the JWT token is signed with an incorrect secret. Since the secret used by the Mobile App Attestation service is not known by the mobile app, it is not possible to reverse engineer it at run-time even when the app has been tampered with, is running in a rooted device or communicating over a connection that is the target of a MitM attack.
The mobile app must send the JWT token in the header of every API request. This allows the API server to only serve requests when it can verify that the JWT token was signed with the shared secret and that it has not expired. All other requests will be refused. In other words a valid JWT token tells the API server that what is making the request is the genuine mobile app uploaded to the Google or Apple store, while an invalid or missing JWT token means that what is making the request is not authorized to do so, because it may be a bot, a repackaged app or an attacker making a MitM attack.
A great benefit of using a Mobile App Attestation service is its proactive and positive authentication model, which does not create false positives, and thus does not block legitimate users while it keeps the bad guys at bay.
The Mobile App Attestation liberates your mobile app to have an embedded secret in its code, instead now it only needs to pass to the reverse proxy or backend the JWT token it receives from the Attestation. Now the reverse proxy or backend can verify the JWT token, and on successful validation they can fulfill requests with a very high confidence that they are originated from what they expect, a genuine instance of the mobile app, with the added benefit of not exposing the API keys to access your Third Party services.
GOING THE EXTRA MILE
I cannot resist to recommend the excellent work done in the OWASP - Mobile Security Testing Guide:
The Mobile Security Testing Guide (MSTG) is a comprehensive manual for mobile app security development, testing and reverse engineering.
Related
I am currently designing a native app which will have a simple username / password login. On a valid authentication, the backend server is issuing a JWT access token and refresh token which are eventually used throughout subsequent API calls.
My concern is that using such an approach, my app can be prone to phishing whereby a hacker can decompile and recompile my app with malicious interceptors.
In order to overcome this, I was thinking of designing my Login API, so that rather than having an accessToken and a refreshToken in the payload response of the API, the Login API will issue a 301 Redirect on myapp://some-path?accessToken=X&refreshToken=Y. This will ensure that if a phishing app is calling my APIs, the accessToken and the refreshToken are sent to the original APP.
Is this a correct approach? If not, which design would be suggested?
How would that help? If I'm going into your app to hack and recompile, I'll be taking over the entire app. I won't leave a copy of the old version, I'm just going to replace the urls. So when you redirect to myapp://somepath, it'll be redirecting to the same hacked app.
Secondly, how would a redirect do anything? Making an HTTP request doesn't cause an app to be launched on the client. It causes the HTTP request to return a HTTPResponse object with a response code of 301. So your redirect URL wouldn't be launched anyway.
Third, that's already too late. By the time you have an access and refresh token, you've logged in. That means the hacked app has your password and credentials. 2FA may help here a bit to make it harder to attack, but only if its time based, and even then it just reduces the window.
If a user is installing a hacked version of your app and is willing to sign into it, you've already lost.
YOUR PROBLEM
I am currently designing a native app which will have a simple username / password login. On a valid authentication, the backend server is issuing a JWT access token and refresh token which are eventually used throughout subsequent API calls.
You need to bear in mind that any secret that leaves the backend or is stored inside a mobile app is no longer a secret, instead it's a public thing, even if you are using TLS (can be intercepted in some scenarios) and Certificate pinning (can be bypassed in some circunstances), because an attacker can reverse engineer your mobile app via a plethora of open source tools and techniques, one of them being static decompilation as you mention:
My concern is that using such an approach, my app can be prone to phishing whereby a hacker can decompile and recompile my app with malicious interceptors.
Once it's decompiled the attacker can do whatever he wants with your code, not just adding interceptors. It's well known problem that the Google Play store is full of cloned and repackaged apps that will use the same backend as the genuine app. You even have a repo RePack: A repository of repackaged Android apps, that illustrates the problem:
RePack is a repository of over 15,000 repackaged Android app pairs collected from AndroZoo. The SHA256 of the apps are available in the repackaging_pairs.txt file. The actual APKs are available in the AndroZoo dataset, which can be downloaded by giving a SHA256 as input. Please following this page to learn how to download apps from AndroZoo.
When repackaged the apps can be used to simply add ads to it and act as a fake app to your service where the profits will go to the attacker, or can be used to distribute malware and/or spy on users as seen in the article 700,000 malicious Android apps found in Google Play store last year:
Google has confirmed that it had to remove nearly 700,000 potentially malicious apps from the Google Play store in 2017 – an increase of 70% from the previous year.
Reverse Engineering
The truth is that anything running in the client side can be reverse engineered
easily by an attacker on a device he controls.
When reverse engineering a mobile app an attacker first step may be to perform a static binary analysis to extract all static secrets and to identify attack vectors, and you can see how in my article
How to Extract an API key from a Mobile App with Static Binary Analysis:
The range of open source tools available for reverse engineering is huge, and we really can't scratch the surface of this topic in this article, but instead we will focus in using the Mobile Security Framework(MobSF) to demonstrate how to reverse engineer the APK of our mobile app. MobSF is a collection of open source tools that present their results in an attractive dashboard, but the same tools used under the hood within MobSF and elsewhere can be used individually to achieve the same results.
During this article we will use the Android Hide Secrets research repository that is a dummy mobile app with API keys hidden using several different techniques.
Another alternative to extract secrets is to perfome a Man in the Middle (MitM) attack to intercept the TLS connection and extract all secrets and learn how the mobile app interacts with the backend and any other third party APIs, and you can see how I done it in the article
Steal that Api Key with a Man in the Middle Attack:
In order to help to demonstrate how to steal an API key, I have built and released in Github the Currency Converter Demo app for Android, which uses the same JNI/NDK technique we used in the earlier Android Hide Secrets app to hide the API key.
So, in this article you will learn how to setup and run a MitM attack to intercept https traffic in a mobile device under your control, so that you can steal the API key. Finally, you will see at a high level how MitM attacks can be mitigated.
Wait, I imagine you now thinking, but I will use certificate pinning to protect my TLS channel, no problem just see how certificate pinning can be easily bypassed in a device the attacker controls in the article Bypassing Certificate Pinning
In this article you will learn how to repackage a mobile app in order to disable certificate pinning and in the process you will also learn how to create an Android emulator with a writable system to allow for adding the custom certificate authority for the proxy server into the Android operating system trust store. This will allow us to bypass certificate pinning and intercept the requests between the mobile and its backend with a MitM attack.
While repackaging a mobile app to bypass pinning is a good solution my preference goes to do it dynamically at runtime as I show in the article How to Bypass Certificate Pinning with Frida on an Android App:
Today I will show how to use the Frida instrumentation framework to hook into the mobile app at runtime and instrument the code in order to perform a successful MitM attack even when the mobile app has implemented certificate pinning.
Bypassing certificate pinning is not too hard, just a little laborious, and allows an attacker to understand in detail how a mobile app communicates with its API, and then use that same knowledge to automate attacks or build other services around it.
Now you may be thinking that you have lost the battle and shouldn't care about adding protections because they will end-up to be bypassed. Well, I have to tell you that software security shares the same traits as the defences in the medieval castles, where they used it in layers, in order to make the assault to the castle as hard as possible, and hopefully impossible. So, you need to adopt the same posture as them and put as many security layers as you can afford, and required by law, in order to make the attackers efforts time consuming and to require more expertise then most of them may have.
YOUR QUESTIONS
In order to overcome this, I was thinking of designing my Login API, so that rather than having an accessToken and a refreshToken in the payload response of the API, the Login API will issue a 301 Redirect on myapp://some-path?accessToken=X&refreshToken=Y. This will ensure that if a phishing app is calling my APIs, the accessToken and the refreshToken are sent to the original APP.
Is this a correct approach?
So, I think that by now is obvious that your solution will not be effective and will be easily defeated with repackaging the mobile app, MitM attack it or simply by instrumenting the code at runtime.
If not, which design would be suggested?
You should use a security approach where the API backend is able to recognize that what is making the request is indeed a genuine and untampered/repacked/cloned version of your mobile app, not just who is making the request, as when user authentication is solely used to protect unauthorised access to an API.
The Difference Between WHO and WHAT is Accessing the API Server
I wrote a series of articles around API and Mobile security, and in the article Why Does Your Mobile App Need An Api Key? you can read in detail the difference between who and what is accessing your API server, but I will extract here the main takes from it:
The what is the thing making the request to the API server. Is it really a genuine instance of your mobile app, or is it a bot, an automated script or an attacker manually poking around your API server with a tool like Postman?
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.
So think about the who as the user your API server will be able to Authenticate and Authorize access to the data, and think about the what as the software making that request in behalf of the user.
POSSIBLE SOLUTION
I recommend you to read this answer I gave to the question How to secure an API REST for mobile app?, especially the sections Hardening and Shielding the Mobile App, Securing the API Server and A Possible Better Solution.
You will see that you can use a plethora of defence layers, like in medieval castles, and that the solution you may want to employ, to guarantee with an high degree of confidence that what is doing the request to the backend is indeed your genuine mobile app, is the Mobile App Attestation.
Do You Want To Go The Extra Mile?
In any response to a security question I always like to reference the excellent work from the OWASP foundation.
For APIS
OWASP API Security Top 10
The OWASP API Security Project seeks to provide value to software developers and security assessors by underscoring the potential risks in insecure APIs, and illustrating how these risks may be mitigated. In order to facilitate this goal, the OWASP API Security Project will create and maintain a Top 10 API Security Risks document, as well as a documentation portal for best practices when creating or assessing APIs.
For Mobile Apps
OWASP Mobile Security Project - Top 10 risks
The OWASP Mobile Security Project is a centralized resource intended to give developers and security teams the resources they need to build and maintain secure mobile applications. Through the project, our goal is to classify mobile security risks and provide developmental controls to reduce their impact or likelihood of exploitation.
OWASP - Mobile Security Testing Guide:
The Mobile Security Testing Guide (MSTG) is a comprehensive manual for mobile app security development, testing and reverse engineering.
I have backend api in Laravel and using Laravel Passport(OAuth2). I see OAuth2 is super cool and secures my auth request (with api middleware in laravel) and allow access only to authorized users.
But i can access the backend api for unauthorised usage for example
Routes: (/register) or (/login) without any api key. Most attackers will see this api call in network tab and can send DDOS attack. Since Laravel Passport has rate-limiting inbuilt, still i don't want people to access my backend api, unless i allow it manually.
What i want:
I have two frontend apps.
Android Native Mobile app.
Nuxt SPA frontend app
My API should work only from these frontends. No other postman or browser request should pass and probably should display unsupported platforms json msg.
OAUTH TOKENS ARE THEY REALLY ENOUGH TO PROTECT YOUR BACKEND?
I see OAuth2 is super cool and secures my auth request (with api middleware in laravel) and allow access only to authorized users.
It allows access to any request that presents a valid OAuth token, not only for authorized users. This is an usual misconception among developers, because the OAuth token only represents who is in the request, not what is making the request, and I discussed this in more detail in this article, where you can read:
The what is the thing making the request to the API server. Is it really a genuine instance of your mobile app, or is it a bot, an automated script or an attacker manually poking around your API server with a tool like Postman?
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.
The article is in the context of a mobile app, but the concept is the same for both the mobile app and web app in terms of knowing the difference between who and what is making the request to the backend server.
UNAUTHORIZED USAGE OF THE BACKEND
But i can access the backend api for unauthorised usage for example
I hope that by now you have realized that is not only your routes to /register and /login that are at danger of being abused, because at the moment you only know who is making the request, not what is making it.
Routes: (/register) or (/login) without any api key.
Even if you have an API key on this routes, it would not prevent it from being abused for credential stuffing attacks.
Why you may ask?
Well in a web app all it's needed to extract an API key is to hit F12 to open the developer tools tab and search for it, or view the page source.
You may now think, oh but in my mobile app it would not be possible, because it's a binary, and I even use obfuscation. Despite being a little more difficult is not hard, because a lot of open source tools exist to help with the task.
Reverse Engineering
You can use a tool like MobSF to reverse engineer any mobile app binary, and extract the API key or any secret from it. I wrote the article How to Extract an API Key from a Mobile App by Static Binary Analysis that you can follow for a practical example of doing it so, and also shows you several techniques to hide the API key in a mobile app with the Android Hide Secrets repo from Github.
MobSF:
Mobile Security Framework (MobSF) is an automated, all-in-one mobile application (Android/iOS/Windows) pen-testing, malware analysis and security assessment framework capable of performing static and dynamic analysis.
If you cannot extract the API key via static analysis, then you can resort to dynamic analysis with open source tools to, like Frida:
Inject your own scripts into black box processes. Hook any function, spy on crypto APIs or trace private application code, no source code needed. Edit, hit save, and instantly see the results. All without compilation steps or program restarts.
Frida will allow at runtime to steal your OAuth tokens and sent them to the attackers control servers, from where they can then reuse it to launch automated attacks to your backend, that will trust they are legit, because the who in the request is valid.
Another approach to steal an API key or even OAuth tokens is to perform a Man in the Middle(MitM) Attack wit another open source tools, like mitmproxy:
An interactive TLS-capable intercepting HTTP proxy for penetration testers and software developers.
So when attacker uses mitmproxy to intercept the request being made to the backend, he will see something like this:
Image sourced from article: Steal that API key with a Man in the Middle Attack
Did you noticed that the url is in https and contains an API Key?
So until now you though that https was enough to secure the communication between clients and server?
WHAT YOU WANT
What i want:
I have two frontend apps.
Android Native Mobile app.
Nuxt SPA frontend app
My API should work only from these frontends. No other postman or browser request should pass and probably should display unsupported platforms json msg.
The web apps
Due to the nature of how the web was built it's not possible for the backend to identify, with an high degree of confidence, what is making the request for any type of web app, be it a SPA or the traditional ones.
The best you can do is to apply User Behavior Analytics(UBA) in a best effort basis to tell appart who and what is accessing your backend:
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.[1] Instead of tracking devices or security events, UBA tracks a system's users.
A good example of using a UBA solution is to use
Google Recaptcha V3:
reCAPTCHA is a free service that protects your site from spam and abuse. It uses advanced risk analysis techniques to tell humans and bots apart.
This is prone to false positives, therefore you need to be careful when deciding to accept or not the request based on the score returned by reCPATCHA V3 for each request:
reCAPTCHA v3 returns a score for each request without user friction. The score is based on interactions with your site and enables you to take an appropriate action for your site.
For mobile apps
By now you are already aware that the OAuth token to identify your user is not that "safe" as you had though initially, because it only identifies the who in the request, not what is doing it, and as you also saw by the plethora of tools available to reverse engineer mobile apps, the OAuth token is always at danger of being stolen and abused by unauthorized clients.
The solution that can let your backend to be sure that the request is indeed from the same exact mobile app that was uploaded to the Google Play store is a Mobile App Attestation solution, and this is a concept that introduces a new approach of dealing with security for your mobile app and backend in an unified manner.
The usual solutions focus to much on the mobile app itself, but in first place the data you want to protect is in your backend server, and it's here that you want to have a mechanism to know that what is making the request is really the thing you expect, your genuine mobile app.
The Mobile App Attestation concept is described in this section of another article I wrote, from where I will quote the following text:
The role of a Mobile App Attestation service is to authenticate what is sending the requests, thus only responding to requests coming from genuine mobile app instances and rejecting all other requests from unauthorized sources.
In order to know what is sending the requests to the API server, a Mobile App Attestation service, at run-time, will identify with high confidence that your mobile app is present, has not been tampered/repackaged, is not running in a rooted device, has not been hooked into by an instrumentation framework (Frida, xPosed, Cydia, etc.) and is not the object of a Man in the Middle Attack (MitM). This is achieved by running an SDK in the background that will communicate with a service running in the cloud to attest the integrity of the mobile app and device it is running on.
On a 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 know. In the case that attestation fails the JWT token is signed with an incorrect secret. Since the secret used by the Mobile App Attestation service is not known by the mobile app, it is not possible to reverse engineer it at run-time even when the app has been tampered with, is running in a rooted device or communicating over a connection that is the target of a MitM attack.
The mobile app must send the JWT token in the header of every API request. This allows the API server to only serve requests when it can verify that the JWT token was signed with the shared secret and that it has not expired. All other requests will be refused. In other words a valid JWT token tells the API server that what is making the request is the genuine mobile app uploaded to the Google or Apple store, while an invalid or missing JWT token means that what is making the request is not authorized to do so, because it may be a bot, a repackaged app or an attacker making a MitM attack.
Taking this approach will let your backend server to know with a very high degree of confidence what is making the request, the same exact mobile app you uploaded to the Google Play, provided the JWT token has a valid signature and expire time, and discard all other requests as untrustworthy ones.
SUMMARY
For web apps your protection is more limited, and in my opinion User Behavior analytics in the backend may be the best option for you.
For mobile apps a huge plethora of solutions exist, but they focus on the mobile app itself, leaving the backend vulnerable to trust in requests that mimic the mobile app, but with a Mobile App Attestation solution the backend is able to tell apart requests from genuine mobile and from fake ones.
GOING THE EXTRA MILE
Now I would like to recommend you the excellent work of the OWASP foundation:
The Web Security Testing Guide:
The OWASP Web Security Testing Guide includes a "best practice" penetration testing framework which users can implement in their own organizations and a "low level" penetration testing guide that describes techniques for testing most common web application and web service security issues.
The Mobile Security Testing Guide:
The Mobile Security Testing Guide (MSTG) is a comprehensive manual for mobile app security development, testing and reverse engineering.
I am implementing SSL pinning in our android app. I have pinned 2 certificates (current and backup) at the client by embedding them in the app.
Now, I want to have a mechanism in place to update these certificates without requiring to roll out an app upgrade in case certificates are expired or private key is compromised. How can I implement that?
One possible solution I am seeing is through app notification. I can broadcast a notification with new certificates and store them in the client. Is there any problem in this approach or is there any better approach?
PUBLIC KEY PINNING
I am implementing SSL pinning in our android app. I have pinned 2 certificates (current and backup) at the client by embedding them in the app.
If you pin against the public key you do not need to update your mobile app each time a certificate is rotated in the server, once you will sign it with the same public key, and you can read the article Hands On Mobile APi Security: Pinning Client Connections for more details in how this can be done:
For networking, the Android client uses the OKHttp library. If our digital certificate is signed by a CA recognized by Android, the default trust manager can be used to validate the certificate. To pin the connection it is enough to add the host name and a hash of the certificate’s public key to the client builder(). See this OKHttp recipe for an example. All certificates with the same host name and public key will match the hash, so techniques such as certificate rotation can be employed without requiring client updates. Multiple host name - public key tuples can also be added to the client builder().
For a situation where the private key used to sign the certificate gets compromised you will end-up in the same situation that you are trying to solve now, that is the need to release a new mobile app to update what you trust to pin against. By other words, the public key cannot be trusted anymore, thus the server must rotate the certificate with one signed with the backup public key you have released with your mobile app. This approach will give you time for a new release, that removes the public key used to sign the compromised certificate, without locking out all your users.
You should always store the backup private keys in separated places, so that if one is compromised you don't get all compromised at once, because then having a backup pin being release with the mobile app is useless.
DON'T DO THIS
Now, I want to have a mechanism in place to update these certificates without requiring to roll out an app upgrade in case certificates are expired or private key is compromised. How can I implement that?
Unfortunately the safer method to deal with a compromised private key is to release a new mobile app that doesn't trust on it anymore. Any remote solution you may devise to update the certificates will open the mobile app doors for attackers to replace the certificates you are pinning against.
So my advice is to not go down this road, because you will shoot yourself on the foot more easily than you can think off.
One possible solution I am seeing is through app notification. I can broadcast a notification with new certificates and store them in the client. Is there any problem in this approach or is there any better approach?
While the mobile app have the connection pinned it can be bypassed, thus a MitM attack can be performed and the new certificates retrieved from the attackers server, instead from your server. Please read the article The Problem with Pinning for more insights on bypassing it:
Unpinning works by hooking, or intercepting, function calls in the app as it runs. Once intercepted the hooking framework can alter the values passed to or from the function. When you use an HTTP library to implement pinning, the functions called by the library are well known so people have written modules which specifically hook these checking functions so they always pass regardless of the actual certificates used in the TLS handshake. Similar approaches exist for iOS too.
While certificate pinning can be bypassed is still strongly advised to use it, because security is all about layers of defense, the more you have the more hard it will be to overcome all them... This is nothing new, if you think of medieval castles, they where built with this approach.
A POSSIBLE BETTER APPROACH
But you also asked for a better approach:
Is there any problem in this approach or is there any better approach?
As already mentioned you should pin against the public key of the certificate to avoid lockouts of the client when you rotate the server certificates.
While I cannot point you a better approach to deal with compromised private keys, I can point out to protect the certificate pinning from being bypassed with introspection frameworks, like xPosed or Frida, we can employ the Mobile App Attestation technique, that will attest the authenticity of the mobile app.
Frida
Inject your own scripts into black box processes. Hook any function, spy on crypto APIs or trace private application code, no source code needed. Edit, hit save, and instantly see the results. All without compilation steps or program restarts.
xPosed
Xposed is a framework for modules that can change the behavior of the system and apps without touching any APKs. That's great because it means that modules can work for different versions and even ROMs without any changes (as long as the original code was not changed too much). It's also easy to undo.
Before we dive into the Mobile App Attestation technique, I would like to clear first a usual misconception among developers, regarding the WHO and the WHAT is calling the API server.
The Difference Between WHO and WHAT is Accessing the API Server
To better understand the differences between the WHO and the WHAT are accessing an API server, let’s use this picture:
The Intended Communication Channel represents the mobile app being used as you expected, by a legit user without any malicious intentions, using an untampered version of the mobile app, and communicating directly with the 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 the mobile app, a hacker using the genuine version of the 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.
OAUTH
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
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.
While user authentication may let the API server know WHO is using the API, it cannot guarantee that the requests have originated from WHAT you expect, the original version of the mobile app.
Now we need a way to identify WHAT is calling the 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 the mobile app, or is a bot, an automated script or an attacker manually poking around with the API server, using a tool like Postman?
For your surprise you may end up discovering that It can be one of the legit users using a repackaged version of the mobile app or an automated script that is trying to gamify and take advantage of the service provided by the application.
The above write-up was extracted from an article I wrote, entitled WHY DOES YOUR MOBILE APP NEED AN API KEY?, and that you can read in full here, that is the first article in a series of articles about API keys.
Mobile App Attestation
The use of a Mobile App Attestation solution will enable the API server to know WHAT is sending the requests, thus allowing to respond only to requests from a genuine mobile app while rejecting all other requests from unsafe sources.
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.
So this solution works in a positive detection model without false positives, thus not blocking legit users while keeping the bad guys at bays.
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
So I recommend you to switch to pin the certificates by the public key, and if you want to protect against certificate pinning being bypassed, and other threats, then you should devise your own Mobile App Attestation solution or use one that is ready for plug and play.
So In the end, the solution to use in order to protect your Mobile APP and 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.
DO YOU WANT TO GO THE EXTRA MILE?
OWASP Mobile Security Project - Top 10 risks
The OWASP Mobile Security Project is a centralized resource intended to give developers and security teams the resources they need to build and maintain secure mobile applications. Through the project, our goal is to classify mobile security risks and provide developmental controls to reduce their impact or likelihood of exploitation.
I am currently developing an android application that uses an API secret and access tokens to access data over TLS.
Instead of storing the secret locally on the app in plaintext I am considering sending it over TLS from something like Firebase. I would send it encrypted and have a method of decryption that is fairly obfuscated. Then the API secret would be used to make requests to the API.
Are there considerations that should be made to protect the keys? My concern is that a malicious entity could decompile the app and insert their own code to find out our method of hiding the API key.
I'm not sure how someone could figure out the key now. I assume they'd decompile the code and redirect the API secret after it's been decrypted.
Eventually, no matter what, I understand that it could be hacked and someone could discover the API secret. How do I then detect that someone has the API secret? They can't hurt other users unless they have their access tokens, which is a different matter, but are there any well-known ways of detecting attacks? The only effect a malicious entity could have is sending many requests to the API servers pretending to be us which would increase our billing, but this should still be protected against. I could rotate my secret but if they already have a method of finding it, then this doesn't do much for me.
To summarize:
What is considered best practice? Should the API secret stay in our servers where we'd make requests from Firebase Functions? How does one detect an attack, or does this depend from API to API? If an attack is detected do I have to force users to update to a new version to make requests and hide the data in a new way in the new version?
I've put a lot of thought into this, but I still have questions I haven't found answers to myself or online. Thank you.
Storing an API key in an app is problematic. You can obfuscate it or hide it in a computation, but if the secret is valuable enough, someone will extract it.
You are on a good track thinking about sending your key from a server. That keeps the key out of the app package itself. You must protect that communication, so TLS is a must, and you should go further and pin the connection to avoid man-in-the-middle attacks.
Rather than sending the key itself, I would send a time-limited token signed by your API key. You'll need to send different tokens over time, but the API key is never directly exposed on the app, and you can change the signing key without requiring an app field upgrade. If a token is stolen, at least it is only valid for a limited period of time.
You still need to make sure you don't send tokens to a tampered app or even a bot who has reverse engineered your protocol. You need to authenticate the installed app package/code as well as check for a safe run time environment (not running in a debugger, no frameworks like frida or xposed, etc.). You could add tamper-detection to your app, but since you're already sending tokens to your app, I think it is a better approach to set up a challenge-response protocol which will cryptographically attest the app. That way you and not the app makes the actual authenticity decision.
For additional background on user and app authenticity, check out a 3 part blog post, starting with Mobile API Security Techniques, or if you prefer video, check out A Tour of Mobile API Underprotection. You can also look at approov.io for a commercial implementation of challenge-response attestation and JWT tokens.
I am writing an android application which will not be available by the google play store. I am looking into how can I accomplish to verify that any user of the application is indeed a verified user.
I would like to use a server for this process that the application is using anyway to send/receive data. My idea was setting up something like a challenge that only verified clients would be able to pass. So anyone using a fake app will not be able to bypass this.
Is there any standard approach to this problem? I have searched a bit but did not find something covering this entirely. Please keep in mind that I am aware of the fact that given the fact the application runs on an android phone which is a device out of my reach there will probably always be ways to bypass the challenges. I am looking to see what the majority is doing in these cases.
There are two probable issues here. First is user authentication (authn) and authorization (authz), and the second is verifying that the client app itself is authentic.
For user authn/authz, I would use some form of OAuth2 with OpenID/Connect. The end result is that you are authorizing your client app to access your end resources on behalf of the user. There are open source and free commercial services available to get you started.
More problematic is authentication of the app itself. API keys are the standard approach here, but these are static secrets which don't do much good if the app is tampered with or the key is observed in the communications channel. No matter how hard you try to hide or compute the secret as needed, if your endpoint is valuable enough, someone will do the work necessary to extract and abuse the secret and then your backend.
You are on a good track thinking about some form of challenge-response protocol. Captchas are the canonical approach here, but they are quite annoying to users on a mobile app and are not always very effective. I believe (and full disclosure, so does my company) that attesting the app's authenticity through a cryptographically secure challenge is a solid strategy. The attestation service challenges the app and analyzes its response. The challenge evaluates whether the app's code has been tampered with and assesses the state of the runtime (is app rooted? running in a debugger? frameworks like frida or xposed present? etc.). The app is issued a short-lifetime token - properly signed if the attestation passes, invalid otherwise. There's no secret in the app, and the app does not make the authentication decision; it just passes on the token to your backend which checks the token lifetime and signature to determine the app authenticity. No token or invalid token and you know this is a bot or tampered app.
For background on user and app authenticity, check out a 3 part blog post, starting with Mobile API Security Techniques, or if you prefer video, check out A Tour of Mobile API Underprotection. I encourage you to also check out approov.io for how this can be implemented as a service.