Best practice for storing and protecting private API keys in applications
Few ideas, in my opinion only first one gives some guarantee:
Keep your secrets on some server on internet, and when needed just grab them and use. If user is about to use dropbox then nothing stops you from making request to your site and get your secret key.
Put your secrets in jni code, add some variable code to make your libraries bigger and more difficult to decompile. You might also split key string in few parts and keep them in various places.
use obfuscator, also put in code hashed secret and later on unhash it when needed to use.
Put your secret key as last pixels of one of your image in assets. Then when needed read it in your code. Obfuscating your code should help hide code that will read it.
If you want to have a quick look at how easy it is to read you apk code then grab APKAnalyser:
http://developer.sonymobile.com/knowledge-base/tool-guides/analyse-your-apks-with-apkanalyser/
As it is, your compiled application contains the key strings, but also the constant names APP_KEY and APP_SECRET. Extracting keys from such self-documenting code is trivial, for instance with the standard Android tool dx.
You can apply ProGuard. It will leave the key strings untouched, but it will remove the constant names. It will also rename classes and methods with short, meaningless names, where ever possible. Extracting the keys then takes some more time, for figuring out which string serves which purpose.
Note that setting up ProGuard shouldn't be as difficult as you fear. To begin with, you only need to enable ProGuard, as documented in project.properties. If there are any problems with third-party libraries, you may need to suppress some warnings and/or prevent them from being obfuscated, in proguard-project.txt. For instance:
-dontwarn com.dropbox.** -keep class com.dropbox.** { *; }
This is a brute-force approach; you can refine such configuration once the processed application works.
You can obfuscate the strings manually in your code, for instance with a Base64 encoding or preferably with something more complicated; maybe even native code. A hacker will then have to statically reverse-engineer your encoding or dynamically intercept the decoding in the proper place.
You can apply a commercial obfuscator, like ProGuard's specialized sibling DexGuard. It can additionally encrypt/obfuscate the strings and classes for you. Extracting the keys then takes even more time and expertise.
You might be able to run parts of your application on your own server. If you can keep the keys there, they are safe.
In the end, it's an economic trade-off that you have to make: how important are the keys, how much time or software can you afford, how sophisticated are the hackers who are interested in the keys, how much time will they want to spend, how much worth is a delay before the keys are hacked, on what scale will any successful hackers distribute the keys, etc. Small pieces of information like keys are more difficult to protect than entire applications. Intrinsically, nothing on the client-side is unbreakable, but you can certainly raise the bar.
(I am the developer of ProGuard and DexGuard)
Another approach is to not have the secret on the device in the first place! See Mobile API Security Techniques (especially part 3).
Using the time honored tradition of indirection, share the secret between your API endpoint and an app authentication service.
When your client wants to make an API call, it asks the app auth service to authenticate it (using strong remote attestation techniques), and it receives a time limited (usually JWT) token signed by the secret.
The token is sent with each API call where the endpoint can verify its signature before acting on the request.
The actual secret is never present on the device; in fact, the app never has any idea if it is valid or not, it juts requests authentication and passes on the resulting token. As a nice benefit from indirection, if you ever want to change the secret, you can do so without requiring users to update their installed apps.
So if you want to protect your secret, not having it in your app in the first place is a pretty good way to go.
Old unsecured way:
Follow 3 simple steps to secure the API/Secret key (Old answer)
We can use Gradle to secure the API key or Secret key.
1. gradle.properties (Project properties): Create variable with key.
GoogleAPIKey = "Your API/Secret Key"
2. build.gradle (Module: app) : Set variable in build.gradle to access it in activity or fragment. Add below code to buildTypes {}.
buildTypes.each {
it.buildConfigField 'String', 'GoogleSecAPIKEY', GoolgeAPIKey
}
3. Access it in Activity/Fragment by app's BuildConfig:
BuildConfig.GoogleSecAPIKEY
Update:
The above solution is helpful in the open-source project to commit over Git. (Thanks to David Rawson and riyaz-ali for your comment).
As per Matthew and Pablo Cegarra's comments, the above way is not secure and Decompiler will allow someone to view the BuildConfig with our secret keys.
Solution:
We can use NDK to Secure API Keys. We can store keys in the native C/C++ class and access them in our Java classes.
Please follow this blog to secure API keys using NDK.
A follow-up on how to store tokens securely in Android