How to store API credentials in android and avoid decompilation attack? - android

My end goal is to keep safe my API credentials and that cannot be discovered by decompiling the apk.
Currently, my API credentials are hardcoded at buid.gradle(app module) file.
When I decompiled my own apk using this site I can able to find the API url and other credentials.
Now I am looking for a solution and more interested to know how "google-services.json" file is getting parsed.
If there is a solution to read **my-cred.json** file under app folder at runtime or compile time (the same directory where **google-services.json** exists), I think I can protect my credentials from decompiling the source( correct me if I am wrong)
Please tell me a way to read **my-cred.json** or any other solution to protect the app credentials

In my opinion there is no way to protect this kind of private keys on your Android device. So the solution is simply not to store it on the Android device. But you can store it on an external server. In my case this key is used onyly once per session, to generate a session token. So I simply created a small java app that create the session token from the user id and the api key. That app is hosted on Google App Engine, but any hosting service should do the work. Then your Android app has to invoke this app (servlet) to get a proper token, which is then used to invoke the API.
I know this does not directly answer your question - but it's quite simple to put in place and will avoid your key to be reverse-engineered.

This is only a partial answer, but before you get into complex obfuscation methods, I would recommend you to first check for each API how they actually authenticate your app: Most API services today require you to register the certificate of your app to work, so even with your API key, one wouldn't be able to use the quota of your app since one wouldn't have access to the private key used to sign your app.

After some research i found out you can't reliably hide an app credential into an android app. Several solutions are being described but none of them is 100% secure , as it is pretty easy to reverse an android app.
You can only obfuscate to make an attacker loose time...
Here are some ways to obfuscate your app credentials , but none of them are really secure even the C++/JNI one. https://rammic.github.io/2015/07/28/hiding-secrets-in-android-apps/.
Only way to have it 100% secure is to set up your own server to hold the credentials and do the login for you, or even requests. I think the best way would be using an OAuth2 authentication process.
It depends on the time you have and your security needs.

Related

Use of FirebaseAuth credentials in an Android .apk

I'm currently looking at an .apk for Android and I came across some hard-coded credentials (email address and password). Apparently these are used for something called FirebaseAuth, which seems to be a Google service.
I'm not very familiar with the Android app development and don't know what the Firebase service is exactly used for.
Is it common to save hard-coded credentials for the service in the app?
What can be done with the credentials?
The credentials do not reflect any information affiliated with me.
I did come across this stackoverflow post, stating something about identifiers, but no clear answer.
edit: I believe my OP was not clear enough.
My question is whether it is normal for Firebase credentials to be stored in an APK or if generally something like an API token should be used.
Usually hard-coded credentials are a bad sign, but I'm not familiar with Firebase.
when setting up Firebase you get a bunch of configuration entries. These are only for in app use and are not related to any user. Your app uses them to connect with the Firebase services. Normally they are stored in a config file within your Android app. So it is totally fine when these credentials are hard coded.
In order to provide a better answer please include some more information about the credentials (f.e. format)

Best practices for API Key and Secret in bundled in App

I'm developing an app that will use text messages to verify a user's telephone number, the usual "enter code" routine.
After reading a little bit it seems like a bad idea to store the private keys for whatever 3rd party I'll use in the app (twilio, nexmo, etc). Somebody could reverse engineer these from my binary and use them in their app.
However, having these on the server doesn't help either, somebody could just reverse engineer my server's endpoint that I use to send text messages and use that instead.
E.g. I could reverse engineer WhatsApp and get the private keys or API endpoints that they use for telephone number verification and just use that in my app, saving me thousand of dollars.
Any ideas on how to protect myself against such an attack?
Hiding API Keys on the server
However, having these on the server doesn't help either, somebody
could just reverse engineer my server's endpoint that I use to send
text messages and use that instead.
Yes it does help a lot.
If somebody gets access to the keys to your web service, they can only do, what your service allows them to do. This is a very good idea to have a web service that encapsulates all the 3d party keys and API - it's way more secure.
Nobody will ever get access to your sensitive keys, that'll allow them to do everything.
For example the 3rd party API allows deleting - your server wrapper API will not allow it.
Moreover, you can add any extra logic or alerts for suspicious behavior.
Hiding API Keys in the app
If somebody sets their mind to it, there's no way you can prevent getting your keys reverse engineered from your app. You can only make that harder. Computer security should never be about "how hard/complicated it is to do", but in this case we have no choice.
Ok, so you have to hardcode the API keys into your source files. It can be easily reverse-engineered.
You can obfuscate your keys, so that they can't be read directly. The result will be that they'll be scattered in a compiled file, rather than comfortably being placed in one place.
On iOS you can use something like this.
On Android you can use DexGuard, or any other way to obfuscate a string.
Encrypting the keys
Another layer of making it hard for hackers is to encrypt the keys.
Here's an example for iOS.
You can do the same for Android.
Perfect Scenario
Ok, so let's say you have a 3rd party API for video management.
The hacker wants to delete all videos on the server, because the 3rd API allows that.
First he has to glue up all the scattered strings in the file. If he manages to do that, he has to find a way to decrypt that.
Even if he manages to decrypt that, that'll give him the API keys to your server and your server and your server only allows to upload videos, not delete them.
I think firebase functions can help us in hiding the third party API keys.
The proposed solution-
Store API keys in firebase as environment variables.
Make a firebase https function that answers to only the authenticated users. If an authenticated user requests it, the secret API key from the firebase environment variable is returned as the response.
Android app does an anonymous login into firebase for the first time, obtains the token.
This token is used as Authorization token in headers while requesting firebase https function. The firebase function would be something like https://us-central1-{your_project_name}.net/{function_name}
I have discussed the approach in detail in this blog and made a sample project

How can I prevent other iOS/Android apps from using my RESTful API?

I have a pre-existing iOS & Android app, that I'm making an update for that includes a RESTful services API and Facebook login for user authentication. The general flow of the app is:
Users "logs in" to my app, via Facebook's SDKs, which return an access token to my app.
App calls a RESTful service, including the Facebook access token as a parameter (using HTTPS and SSL)
Service that is called, sends the received access token (and app secret stored only on my servers) to Facebook to verify who the user is, and performs actions based on that. Facebook is set to require app secret from server-side calls.
My app has gained popularity and has several clones already, and I want to prevent these clones from being able to use my RESTful API (as I am sure that they will try to do when I release the update). Let's assume that the clones are smart, are using the same Facebook access tokens that my app does (if this is possible), and are following a similar pattern & frequency of calling the API that my app does.
Is there anyway to ensure, or nearly ensure, that calls to my services are coming only from my app, and not the clones?
Thanks in advance!
You can do this by including a signature in the request, and verifying it.
App Side:
do something like: signature = md5( md5(url + data) + MY_RANDOM_KEY)
append signature to the data, or url, etc.
send call to REST api (as usual)
Server Side:
extract the signature from the body/url (and remove it from there).
calculate what you think it should be: signature_should_be = md5( md5(url + data) + MY_RANDOM_KEY) [keep in mind you've removed signature from url/data so that you get url/data in its original pre-hash state]
verify that signature and signature_should_be are equal
Doing this, along with SSL, should make your API secure enough.
You could do as Tommy Crush suggests and add a secret inside you application. But if you are up against clever opponents, this probably won't help. The attackers can either decompile your application or try to simply reverse engineer your signature algorithm.
It is important to remember that anything stored within your application should be thought of as already compromised, as an attacker can decompile your app and scour through your code as much as he/she pleases and extract anything he/she wants from it. You cannot rely on anything in your application to be safe inside your app, since an attacker can extract it from your app into their app.
It is important to note that you are using trying to use OAuth for authentication, which is not intended for. It is simply meant for authorization, which is not the same as authentication. Authorization simply gives you access to a resource, but does not tell you who accessed it, which is the problem you are facing. To authenticate your users as your real users (or as close as you can get), you would need to add a login service for your service - something like rolling your own OAuth-server, or similar. Then you can decide who can access the resource, which in this case is your RESTful API :)
If this is more work than it is worth, then Tommy's scheme is a good alternative :)
The de facto solution for authentication on restful APIs like Twitter and Facebook use is the OAuth mechanism.
You can find more details here: http://en.wikipedia.org/wiki/OAuth.
OAuth is supported from the majority of the languages with external libraries.
On Android for example there is the https://github.com/wuman/android-oauth-client library.

Securely storing credentials

Our app needs to ship with several usernames, passwords, and tokens for accessing other web based services. I have done quite a bit of googling on this but cannot figure out how to ship the app with the credentials stored securely. Any advice on how to achieve this would be appreciated.
at the end of the day what you're packing in an .apk file is a Java bytecode that if you Google "reverse engineer java byte code" you'll tools and tutos on how to extract the information on that file. I can think of a few good practices that will help you make your app more secure depending how far you're willing to work on it:
pro-guard: that one is a giving, use pro-guard!
you can use little tricks to make stuff more complicate, to store all those Strings in an encrypted format and decrypt them on run time.
as a nice add-on for the last point: on your Developer console, you'll find "YOUR LICENCE KEY FOR THIS APPLICATION". You can use that key to cript the information during development time, and during runtime acquire the value from Google Play to use it to decrypt. More info about it HERE
This license key can also be used to verify app authenticity.
You could also built those keys as a native library. Strings stored in C++ compiled code are way more complicated to crack than in bytecode.
all in all, might be a good read for you this link: http://developer.android.com/training/articles/security-tips.html
Since it has to be decrypted for the application to use there is no way to securely do it, unless you have the person download the information after they install, but there will still need to be information to get to the data for the application to use it.
The most secure way, if you don't want to trust the user, is to have them send the request to your server, and then your server uses its own credentials to go to the website of interest and return the data back to the user.
This way the data stays protected in one place.
Otherwise someone can get to the credentials if they try hard enough.

Should I obfuscate OAuth consumer secret stored by Android app?

My Android app contains OAuth consumer secret for Twitter's API. At the moment it's in .properties file in plain text, so it takes zero effort for someone to look it up in APK.
Should I take steps to obscure it (like, rot13 or stored in obfuscated Java code)? Or should I actually avoid doing any of that, as it would create false sense of security?
How do people usually distribute/store OAuth secret in Android apps?
How common it is for the secret to be stolen and abused?
The real question is what does an attacker get from stealing it...
You should do your best to protect secrets but at the end, a highly motivated hacker can always get to it in an installed app. So it's the value of the secret vs. difficulty of extraction.
The value of the client secret is impersonating the application. It doesn't give any access to user data. However, since Twitter supports automatic issuance of credentials to previously approved apps (their sign-in with Twitter flow), an attacker can potentially build a web app with your secret and steal user data using a blind redirect.
The problem with Twitter's implementation is that they do not ask the developer about the nature of the application. If they did, they would not have issued you a secret to begin with, and would block anyone building a web application using your client credentials and stealing data from users who already approved it.
Obfuscating is one option, but a weak one. Moving the secret to a web server acting as an API proxy is another, but that just moves the problem elsewhere because now your app has to authenticate against the proxy server. However, this pattern can be reasonably secure if you require users to log into your site (which can use, via web views, Twitter to log in). This way, someone trying to abuse your proxy will need their users to open accounts on your service, which isn't very appealing.
In short, go ahead and obfuscate it. It doesn't hurt. Consider using the proxy pattern too. And maybe let Twitter know their security policies are "not great".
I would definitely read this analysis by one of the OAuth authors, Eran Hammer-Lahav, which cites another article dissecting Twitter's OAuth secret problems.
My advice would be to obfuscate the key so that it cannot trivially be extracted and you should be safe from chancers and spammers.
Hammer-Lahav's opinion is that OAuth secrets should not be revoked and should merely be used for gathering statistics. Hopefully Twitter are following this advice.
To hide your OAuth secret keys in your Android app you can use the gradle plugin we have developed. It is a free open source alternative to Dexguard. Our hidden-secrets-gradle-plugin uses the NDK and XOR operator to obfuscate keys to prevent reverse engineering.
You can optionally provide a custom encoding/decoding algorithm to improve the security of your key.
Access to the plugin and all the details : https://github.com/klaxit/hidden-secrets-gradle-plugin
Main point of 0Auth is that you do not store any precious sensitive information on device -
so it is ok to store secret on device (much better that real user credentials). In case your device secrets are stolen, user can always invalidate access without need to change his credentials

Categories

Resources