Android Makers is over! With over 650 participants and 50 sessions over 2 days in Paris, it was a lot of fun! It was nice to see everyone in person again and discuss all the Android things (and ๐ป too)!
This year, we decided to rewrite the Android app (github) in Jetpack Compose and this too was a lot of fun ๐! We got a functional app in no time and sent it out for public scrutiny. We got a lot of feedback and contributions (did I mention this community rocks? ๐ค๐)!
This is the story of how (and why) we made our google-services.json
public so that anyone could easily contribute.
About google-services.json
Whenever you setup a Firebase project, google-services.json
comes up pretty quickly in the installation instructions. You usually download it from the Firebase console:
If you open it, you'll find something like this (some values redacted although I'm not 100% sure why, more on that later):
{
"project_info": {
"project_number": "378302699578",
"project_id": "openfeedback-am-2022",
"storage_bucket": "openfeedback-am-2022.appspot.com"
},
"client": [
{
"client_info": {
"android_client_info": {
"package_name": "fr.androidmakers"
}
},
"api_key": [
{
"current_key": "[redacted]"
}
],
}
],
"configuration_version": "1"
}
As you can see, there's something called api_key
up there. That sounds pretty secret so certainly it's a good idea to hide it, right? Well... turns out it's not secret at all.
Your Android API key is not secret!
Because your app needs your API key at runtime, the API key must be accessible somewhere in the app. So really it can't be secret. To prove it, let's try to retrieve it.
Start by doing a google search for the Android Makers app apk. This takes you to an ApkPure website that allows you to download the apk:
A click and and a few downloaded MB later, you can open that APK in the Android Studio APK analyzer (Build -> Analyze APK...). Look for a resource that looks like an API key. This google_api_key
string sounds like a good candidate ๐:
Yup, zoom a little bit... That's the one! So I'm not sure why I redacted it above. Certainly because everything is made to make you believe this should be treated as a secret.
Scary warnings
If you ever commit such an API key to Github, all the repository admins will receive an email along these lines:
Well, that's scary ๐...
Same thing if you publish an app to the Google play that contains your API key in Kotlin code:
This is also scary ๐ฑ...
Why all these warnings if the API key can be retrieved in a few minutes by any malicious user? That remains a mystery to me. My current guess is that there's no way to distinguish between a client key and a server key so that warning is sent to anyone indiscriminately. If someone can see of a good reason to show these warnings for an Android API key, please tell me so I can edit this article and redact everything for good ๐ (and invalidate all the things too!).
Developing in the open
After browsing the web a bunch, realising that there was an official answer in the firebase forums (edit: and it's even in the official Firebase documentation as @zsmb13 made me realize later) and double checking that the values were in the apk anyway, we decided to ignore the scary warnings, stop living in fear (๐ค) and commit our google-services.json
!
Now anyone can develop for the App using the real data. Special thanks to @underwindfall
, @R4md4c
and @oldergod
for their awesome contributions ๐!
What could go wrong?
Assuming someone has your Android API key. What can they do with it?
In our case, the main thing was using our Firestore instance and using our quota. We could imagine someone developing their own service squatting our Firestore instance and therefore not paying the bill at the end of the month ๐ธ.
While technically possible, I'm not sure how practical that would be. Such a service would be dependant on a completely foreign infra and any change would break it almost instantly. I'm not aware any such attack has happened already but maybe it's a matter of time...
Additional (actual) restrictions ๐
The good news is that the Google Cloud console allows to restrict the API keys ๐
Platform restrictions
You can restrict your API key per platform:
In the example above, we restricted the API key to only be callable from Android apps. As @RickClephas points out on Twitter, this works by using two HTTP headers: X-Android-Package
and X-Android-Cert
. So it's not bullet proof but it's still something.
APIs restrictions
In addition to platforms, you can also restrict your API key to some APIs:
This makes sure no other APIs can be used so it's an additional safety. Make sure to include Firebase Installations API
and Token Service API
or your app will stop working after a few calls.
If your feedback was not counted during Android Makers, this is what happened ๐
. Thanks to Hugo Gresse and @GerardPaligot
for catching this!
Conclusion
You can hide your Android API key from Github but this is not going to prevent anyone to get it. If you need to share it with colleagues or your community, it should be pretty safe to commit it despite all the scary warnings.
At the end of the day, security is never a "yes" or "no" kind of question and has more of a continuum of answers. Some might argue that despites all the flaws, hiding your API key from GitHub is still making it harder to retrieve and that's very true. It's also very true that every security measure has a cost, either in terms of raw dollars or in terms of developer experience.
Of all the possibilities:
- Add GCP API key restrictions
- Fine tune your Firestore security rules
- Check your app integrity with something like Firebase App Check
- Obfuscate your client code with something like DexGuard
- Implement server side rate limiting and fraud detection
- Hide your API key from Github
I'd argue that hiding your API key from Github is the one with the worst cost/security ratio. If you're relying on that for your security, you'd better add API key restrictions and double check your Firestore rules instead.
Note: none of the above applies to server API keys of course. If your API keys doesn't end up in a client, make sure to keep them secure in the depths of your infra.
This article was edited on May 10th to add a note about the Firebase official doc, the X-Android-Package
and X-Android-Cert
headers and rework the conclusion to display more possible solutions.
Many thanks to Dorian Cussen and Edouard Marquez for proof reading this article
Cover image background by Claire Tresse