Let us start with a simple use case:
Imagine we have to build a web app where you can enter an address and you get the latitude and longitude for it.
For this app, we want to use the Google Maps Geocoding API. To get the information we need, we have to do a GET
API call. Providing the address
as well as a key
, which is the Google API key:
https://maps.googleapis.com/maps/api/geocode/json?address=ioki%20gmbh&key=[GOOGLE_API_KEY]
But how do we get the API key?
First, we need a Google Cloud project. Go to the Google Cloud console and create one. Initially, the project is “empty”, of course. There are no Google API keys or something.
But obviously, we need one. So we have to go to the Credentials page and create a new “API key”.
Nice, we have an API key. But we are still not able to use the Geocoding API. Why that? Because the next thing we have to do is to enable the Geocoding API in the Cloud console.
Go to the API Library and search for the Geocoding API, and click Enable
.
Note: I don’t want to take over the process of “enabling billing” at your Google Cloud console as it will distract us too far from the intent behind this post. But nervetheless you have to do this as the Geocoding API is not free to use.
Here, generally speaking, we are telling Google what APIs are enabled for this Google Cloud project and therefore accessible with the API keys.
That’s it 🎉.
Finally, we can use our created API key in the URL I posted above and you will see the results.
But, hold on!
There is a serious security issue. The just created API key is useable for literally everyone. And therefore, in case someone steals the key, can use it and you get charged!
But there is more. Imagine you enable another API. This “specific” Geocoding API key would have access to this other API as well!
Want to know how to fix it? Then read on!
Imagine, a friend of you is an Android developer and wants to create an Android app for our web app. But he doesn’t want to display the latitude and longitude only, but also an image next to the given address.
For that, he wants to use the Google Maps Places API. First, he gets the photo information via a Places Search request, followed by a Places Photos request.
Of course, the Places API has to be enabled on the Google Cloud console. The Google API key has to be packed (and shipped) within the APK (the file format of an Android App).
This works and everyone is happy.
Until…until you get a high bill from Google.
No, joke aside. But what could happen is the following:
Since the APK has to store the API key, and since an APK is basically just a ZIP file, the API key can be simply extracted and used by an potential attacker. And the attacker would have then access to all enabled Google APIs, with a single API key.
But there is help: Restrict your API keys to specific applications and APIs.
For that, you have to go to the Credentials page again and click on the specific API key. There you can restrict the key for a special application (like web, iOS & Android) as well as selecting the Google APIs you restrict the key to.
In the example above, you see an API key with the name Ham**
. It is restricted to use by an Android app with a specific ApplicationId
as well as the signing fingerprint of the APK. The key is furthermore restricted to be used by the Places API and the Maps SDK for Android only.
This key is now unaffected, in case you (or a teammate) enable another API on the Cloud Console. It will always stay like it is until you adjust it again.
You might ask yourself that something like this will not happen to you.
I would agree if you build something for yourself. But imagine you work at a company where multiple people have access to the same Google Cloud project. You don’t know what they do.
Think about the following:
Maybe there is an Backend team, who just enables APIs for their specific use case. Meanwhile, the Android team uses an unrestricted API key on the same Google Cloud project. The used API key, which is already shipped to thousand of devices in the world, is a security issue now!
Luckily I have one more case you have to think about: Firebase
A Firebase project is basically an Google Cloud project. Therefore, all that I’ve written above applies to Firebase projects as well.
“But I heard that Firebase keys are safe to expose”, you might say. As you have probably read this famous StackOverflow answer from an Firebase employee.
I have to admit, yes, he is right. But only as long as you do not enable additional Google APIs on the Google Cloud project which is linked to the Firebase project 💡! Which is also documented. Even it is a little bit hidden.
Take the following into account.
The Firebase web setup gives you a code snippet like the following:
<script>
var firebaseConfig = {
apiKey: "AI***************nc",
authDomain: "*******.firebaseapp.com",
projectId: " "*******",
storageBucket: " "*******.appspot.com",
messagingSenderId: "65********66",
appId: "1:65********66:web:6a******************8f"
};
firebase.initializeApp(firebaseConfig);
</script>
This code snippet has to be placed in an HTML or JavaScript file. As you might know, this will be shipped to the clients. This means everyone who has access to this website can right-click in the browser and say “View Page Source” and… right, view your API key.
Imagine you, or someone in your company enables an additional API that may cost you something. The (Firebase) Google API key, which is literally public to everyone who has a browser installed, is a potential security risk!
Again, as long as you don’t change anything on the Google Cloud project, it is safe to have the API key exposed. But you will never know what your teammates do!
So please keep that in mind, in case you create a Firebase project in a team.
I hope I could give you some insights into this topic. I know security topics are not even once. To be honest, it’s not even my topic 😀. But since we discovered recently such a case with one of our API keys I thought I shared my learnings with others so that you (hopefully) don’t have to find out all of this by yourself.