In my Android app, I make requests to my backend API and add a auth header value so that only my app can access my API data. I'm using OKHttp which makes it simple .addHeader("name", "value")
However, right now I'm simply hardcoding this header name and value in my Java file. It seems that people are able to decompile Android apps and will be able to see my auth header value.
Is there a way I can prevent this from happening?
This is a very discussed topic and it's always a tradeoff.
Some strategies are
Hardcoded in Java
In shared preferences, assets or resources folders
Using the NDK
Public/private API key exchange
Article's conclusion
What option you choose is probably going to be determined by how much control you have over the backend server. If you don’t have any control then you’re probably going to have to hide the API key using the NDK. If you do then we recommend the Public/Private encryption of the API key using nonces to prevent any replay attacks. In the next article we’ll look at the security implications of supporting earlier Android OS versions, as well as how some Android phones are more secure than others.
Subscribe to our Android Developer Newsletter
Join our Android Developers newsletter to get all the top developer news, tips & links once a week in your inbox
Full article
Possible duplicated question/answer
Related
I am developing an SDK/API that will be used by apps not written by me.
I want my code to generate a private key once and store it on the device.
This key should be unique per device, I don't mind it being erased on factory reset, and I don't need to extract it from the device.
Sounds an ideal case for the KeyStore (preferably with a StrongBox).
I do want, though, different apps to use the same key to sign (or ask my API to do so)
I could not answer two concerns:
If my API is a library linked (statically) into the app, different apps using my code wouldn't be able to use the key, because the keystore requires
If I package my API as a separate android app, and have the other apps use it using Intents, I'll have to have the user install it manually, because as far as I could tell, Android/Play does not allow for dependencies between apps.
What is the most graceful way to resolve this situation?
I have been doing some security testing on an Android app. One thing I am trying to wrap my head around is API key security; particularly google Places and Maps keys. There are lots of posts that talk about the options, namely compiling keys into source, placing them in resource files, compiling them into a shared library, etc. In my particular case, the Maps key is in the manifest file, and the Places key is in a shared library. I created a signed APK to test how hard it would be to obtain and use one of the keys. I did the following:
Reverse engineered the APK using apktool,
Opened the manifest and grabbed the Maps key,
Created a fake version of the application with the same package structure as the original containing an activity with a google map fragment,
Put the Maps key in the fake manifest,
Ran the application, which displayed the map
Then I:
Created a new class in the fake app with the same package and name as the original with code to load the shared library from /data/data/[package name],
Copied the the shared library from the reverse engineered APK to the /data/data/[package name] folder of the fake app,
Ran the fake app, which then printed out the Locations API key
So in the end, without much effort, I had both keys which I could then use in a fake version of the application.
I'm sure I must be missing something. It looks like the only option for Maps is to store the key in the manifest. What is stopping someone from doing what I did? Surely it can't just be indifference. I realize that someone would probably get caught if they tried to publish their app using a hijacked API key. However, someone could create an app and have people side load it. It would be a huge disruption for customers if the company had to change a hijacked key every time someone messed with it.
I believe you need to go through the Docs for Google API keys again. There seem to have something called restrictions that should be able to help with you ensuring that your Keys are protected and not used on some other application.
I believe that restrictions prevent a request from other domains you have not included from not being able to render.
API Key best practices
There are many way to keep your API key secure. Below links are explained that how to secure your keys.Depending on your use case you can follow one of them
Using Gradle
Using NDK
Using Server Call
This question already has answers here:
Best practice for storing and protecting private API keys in applications [closed]
(13 answers)
Closed 5 years ago.
After having researched the issue to great length, we have not found a valid solution for our situation.
We have API keys for external SDKs and APIs which we are using in our app.
This link says to bind your key to a signing certificate. This is great if you have your own SDK or API, but for external elements where you have to provide your assigned key as a parameter, this is not an option.
The following link does not apply to our situation.
Implementing (secure) Api Keys in an app
In addition, we have spent three days of trying different configurations as well as the ProGuard UI attempting to obfuscate our code using ProGuard without success.
We have also implemented AndroidManifest.xml key references, but they are clearly visible in a generated config.java class. Thus, this is also not a viable solution.
Securing source code is a minor priority. Our main concern is the security of the API keys.
Can anyone provide a possible solution? Is the DexGuard product a real solution when we cannot get ProGuard to work with a simple project?
You can always use firebase remote config
That way you also can change you key without the need of upgrade
Firebase Remote Config :
Mentions :
Don't store confidential data in Remote Config parameter keys or parameter values. It is possible to decode any parameter keys or values stored in the Remote Config settings for your project.
So, it would not be a good mechanism for storage of API keys
I have a SDK which is being used by many merchant applications. As all these applications use my SDK I want to expose the key stored in android keystore system generated by one application, to all the applications on that device. Is this possible in the current Android Keystore System?
Is it possible to make it world readable, similar to shared preference?
If this feature is not available then what would be a good method to do it as merchants will not let their APP being used as way of authenticator.
I checked the following links for possible solutions. After going through these links I understood that the key will be accessible to the app generates it and application can access it by reflection.
link
link
link
link
link
The apps we write will soon be enhanced by downloadable "packages" using the in-app purchase API. We would like therefore to start securing our content which we wish to allow the users to download/extract onto their memory card (so as to not use up internal memory for our large applications), however, we need to secure the files somehow so that they can't simply be taken from the SD.
Can anyone suggest some possible/simple/common techniques used to do so on Android?
You'll want to look into ProGuard, it's pretty well integrated with ADT. An easy way to get a good ProGuard config file is to create a new Android project in Eclipse, as the newer versions of ADT automatically make one for you. It is used when you right click the project and use Android Tools>Export
I'd think you'd probably want to generate a hash based on some unique device identifier and a strong key of your choosing. A unique identifier for the device can be generated using the technique discussed in this answer. Have the App transmit that hash to your server, and encrypt the package before (or as) it is sent to the user using this hash as a key. Your app will decrypt the data as it is read by generating the key on demand (the same way it was initially generated). Have a look at the MessageDigest class and the javax.crypto package in the API.