When creating a new project Firebase generates browser API keys automatically in the GCP API credentials. This is the same API key that is set in the Firebase Web client SDKs and is publicly available.
By default the key has no restrictions, so it's prone to quota stealing for every API enabled for that project. Surprisingly I have not found information about securing this key in the Firebase documentation.
So I took two extra steps to secure the key:
Added HTTP referrer restriction to allow requests from my domain only.
Added Identity Toolkit API to the list of allowed APIs. Experimentally I've figured out that it's enough for Firebase Auth and Firestore to work.
Added Token Service API. This is needed for refresh tokens to work and keep the authentication.
My question is mostly related to points #2-3. What are the APIs that needs to be enabled for various components of Firebase to work on the web?
I also enabled those same two APIs, but I used the Metrics Explorer to see what the various Firebase-created keys had been using based on actual traffic.
In GCP,
Go to Monitoring -> Metrics Explorer
Click 6W in the time range above the graph
Resource Type, start typing consumed_api and select it
Metric, choose Request Count
Group By, type credential_id, select it, then type service, and select it
Aggregator, select sum
By now, the legend for the graph should list all the credential ids and which services they used in the last 6 weeks. You should be able to figure out the APIs from the service.
You can use Filter to filter by credential_id if the results are too noisy.
By default the key has no restrictions, so it's prone to quota
stealing for every API enabled for that project.
This is indeed possible and I am able to make e. g. Google Maps API call with the auto generated Firebase API key.
Such preconfigured behaviour was certainly unexpected and I am now experimenting with the restrictions as per the extra steps described in the original question.
Related
In short: In GCP credentials can be restricted with application restriction and with API restriction, but Identity Toolkit API cannot be restricted on Expo mobile application.
-In web both restrictions work
-On android/iOS API restriction works but (as I have tested, correct me if I'm wrong) application restrictions does not
Now if using email/password authentication there is an issue.
There is a huge insecurity here as if anyone gets to know your API key (you define in initializeApp and so you connect to Firebase with and so use with Identity Toolkit API).
They can only by knowing that key call Firebase Auth REST API "Sign up with email / password" from anywhere and create users for your project!!
Am I wrong, missing something or can this be prevented somehow?
Things you can do to prevent this:
In "GCP>credentials>Identity Toolkit API" you can lower "Queries per minute" and "Queries per minute per user"
You can in "Firebase>Authentiction>Sign-in method>Manage sign-up quota" lower the quota from same IP address to minium (but does this help in case of android/iOS application?)
But there is no completely secure solution unless you can application restrict your API key as far as I know.
I got the following answer from Firebase support and since there has not been answers I will add this as correct answer for anyone looking solution for same thing or seeing this question.
First of all, I would like to thank you for choosing Firebase to
implement your application. I know that these kinds of situations
could be frustrating, let's work together to provide the best solution
for you.
I have checked your case and I would recommend that you reinforce your
Security Rules, because this is not a security risk, as long as you
secure access to the data within your project correctly for your
requirements, as it is mentioned in this external entry.
We don’t have a way to know the origin of those emails, even if they
were created by real users through your app, but if you identify fake
accounts you can use Cloud Functions to delete all emails registered
with that pattern using Auth triggers. Alternatively, you can delete
the accounts after an established time without activity using Schedule
Functions.
Additionally, if you don’t want to have users on your application, you
would probably need to use the Admin SDK and authenticate the
application by service account instead.
We're currently working on our API based on Google Cloud Functions together with Google's API Gateway.
As every customer who buys access to our API should get their own API key, I'm wondering if there's a ways to create those API keys using and API. What I want to achieve is that a customer is able to request an API key in their own settings, so klick a button, this triggers a function, generates a key and shows it to the customer in front end.
After searching for quite some time, I didn't find anything about how this could be built. It could also be that my approach to this is totally wrong - if that's the case, please roast me and give me some advice with it!
Thanks in advance for your answers!
Google credentials can not be created programmttlcy they must be created manually.
In fact, there is something. A while in beta (more than 1 years ago) and quickly back in alpha, and undocumented (or pretty bad)
As you can see in the gcloud alpha command, you can use API Keys with CLI and API. Use this command to test and discover more how you can use API keys.
gcloud alpha services api-keys create --display-name="created by API" --log-http
USE WITH CAUTION
Firstly, I have no update on this API, will it survive or not? The lifecycle and the "no news" from Google is strange and keep in mind that the API can be removed at any time.
Secondly, API Keys is a long lived token and it's not recommended for security reason. But sometime, it's better than nothing, so to use it when no others solution are possible, it's acceptable. Else, prefer OAuth .
Eventually, API Keys authenticate a project, not a customer/user. You won't have it in header data after the API Gateway request forward. Only the Project ID (or Number, I don't remember). Thus, if you want to differentiate each customer/user, you need to create different projects, and generate a keys in each project. Same thing if you implement rate limit on API Gateway: Quotas are per project and not per API Keys.
Im going to make an app which uses Google Maps API. We all know it isn't free for searching etc.
This API KEY needs to be saved in the app code which can be reverse engineered and extracted.
What if someone uses botnet + my apk file to drain my Google Maps account?
You can see the $$ high amount bill if your API key is not restricted.
For restricting it, Follow the below steps:
To set an application restriction for an API key
Visit the credentials panel.
Select the API key that you want to set a restriction on. The API key property page appears.
Under Key restrictions, select Application restrictions.
Select one of the restriction types and supply the requested information following the restriction list.
Android apps
Add your package name and SHA-1 signing-certificate fingerprint to restrict usage to your Android app.
Below the types, add the SHA-1 signing-certificate fingersprint and your Android package name from your AndroidManifest.xml file.
iOS apps
Accept requests from the iOS app with the bundle identifier that you supply.
Below the types, select the appropriate iOS bundle identifier from the list.
Click Save.
The restriction becomes part of the API key definition after this step. If you fail to provide the appropriate details or do not click “Save”, the API key will not be restricted.
I've looked at a few places, Including this post and the firebase panel
Is there no way to use these api's to secure these endpoints using an api key you create per client who uses your cloud functions?
I'm able to block every one putting a restriction on the Browser key, but I would like to create a new api key, and use that as a way to authenticate my endpoint for various clients.
Creating a new api key, and using that as a parameter in my query doesn't work (don't now if I'm doing anything wrong)
Is there a way to do this?
Option 1: handle authentication within the function
https://github.com/firebase/functions-samples/tree/master/authorized-https-endpoint
Adapt above to use clients/keys stored in firestore
Option 2: Use an an API Gateway
Google Cloud Endpoints (no direct support for functions yet, need to implement a proxy)
Apigee (higher cost, perhaps more than you need)
Azure API Management (lower entry cost + easy to implement as a facade for services hosted outside Azure)
there are more..
The above gateways are probably best for your use case in that the first two would let you keep everything within Google, albeit with more complexity/cost -- hopefully Endpoints will get support for functions soon. Azure would mean having part of your architecture outside Google, but looks like an easy way to achieve what your after (api key per client for your google cloud / firebase functions)
Here's a good walkthrough of implementing Azure API Management:
https://koukia.ca/a-microservices-implementation-journey-part-4-9c19a16385e9
Not to achieve what you are after, as far as firebase and GCP is concerned your clients is your specific business problem.
One way you could tackle this (with the little information that is provided);
You need somewhere to store a list of clients + their API key (I would use firestore)
For the endpoints you want to secure with a client-specific API key you can include a check to confirm the header exists and also exists in your firestore client record.
Considerations:
Depending on your expected traffic loads and the the number of firestore reads you'll be adding, you might want to double check this kind of solution will work for your budget.
Is the API-key type solution the only option you must go for? You Could probably get pretty far using the https://github.com/firebase/firebaseui-web and doing user checks in your function with no extra DB read required. If you go down this path most of the user signup/ emails / account creation logic is ready to go.
https://firebase.google.com/docs/auth/web/password-auth#before_you_begin
Curious to see what some other firebase users suggest.
Is it possible to either turn off the api explorer completely or limit the access to it?
I noticed some logs in my app that come from failed requests executed from a browser. My api is only consumed by an Android app so the only place where they can come from is the api explorer. Also the api access is limited to 1 web and 1 android client id.
Unfortunately no. The API explorer works by using the Discovery Service associated with your API, which is not actually part of your backend, so you can't specify auth or visibility for those URIs.
The list method from the Discovery service is used to generate the list on the APIs Explorer app using your app as base:
discovery.apis.list:
your-app-id.appspot.com/_ah/api/discovery/v1/apis
When someone clicks one of the APIs from the list, the full discovery document is retrieved for that apiName and apiVersion using the getRest method from the Discovery service:
discovery.apis.getRest:
your-app-id.appspot.com/_ah/api/discovery/v1/apis/{apiName}/{apiVersion}/rest
If you are looking for ways to prevent the executing of the API, check out Cloud Endpoints: Control who can execute API through API Explorer
endpoints makes auth easy and you can get the current user. You should use auth to ensure people don't mess with your private apis - otherwise people could trace what kind of post or get requests you're sending anyway - auth is always a good idea rather than trying to keep your apis secret.
If you're building a secret product and you don't want your competitor to find out, you could perhaps use some obfuscation method on the backend and on your client which makes the apis unreadable.
Also a user messing with your apis shouldn't break your database - or if it does - it should only break it for the user that was being foolish. Having logic in your client for how apis are used so that the backend doesn't break is a bad idea - the backend apis should take care of themselves and not worry about how or why they are used and who by for what purpose.