Why does my Firebase project work without specifying the apiKey? - javascript

I have set up a Firebase project that uses the Firestore database. i was given the following snippet to use it in my Javascript code:
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
authDomain: "xxxxxxxxxx.firebaseapp.com",
databaseURL: "https://xxxxxxxxxxxxx.firebaseio.com",
projectId: "xxxxxxxx",
storageBucket: "xxxxxxxxx.appspot.com",
messagingSenderId: "xxxxxxxxx",
appId: "1:xxxxxxxxxxxxxxxxxxxxxxxxxxx"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
All was working to that point. I then needed to ensure that only my domain could use the app, by setting up authorized domains on the firebase project, as well as on the apiKey in the "credentials" menu from the Google Cloud Platform project.
My project still worked to this point, but I noticed that it still worked from any domain. So the restriction was not working. Actually, with more testing, I found out that the apiKey was not even necessary for my project to work, and I can reduce the snipet to the following and things still work:
// Your web app's Firebase configuration
var firebaseConfig = {
projectId: "xxxxxxxx",
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
So I am wondering: how can my project run and write in the Firestore database with only the projectId given? I am given a bunch of information in the snippet that is not even necessary.
Does anyone have an idea why this is happening to me? I tried to create a new project, following different tutorials again, with the same result. Actually, one of the tutorials I used has the same behaviour, as i can use this tutorial's project (it is actually online), just by specifying the projectId and I could make it's Firestoere quota run out by spamming it from my local server.
I can't find any information about a similar case to mine. Please help.
PS: here are my Firestore database rules, if it matters:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}

Every Firebase project is actually a Google Cloud project, and each cloud project has a unique ID. Since there can only be one Firestore instance per project, it's sufficient to use just the project ID to locate it.
Other values from the config file are used for other Firebase products. If you don't use those products, then you don't need them. Feel free to leave them out if that suits you. Bear in mind that you might run into problems in the future if you don't use the full configuration.
If you are concerned about the security of your Firestore instance, you should be using security rules to limit who can read and write what data. It's not possible to limit access to it based on the domain of your web app, or the location of the user. The rules you have right now allow anyone with an internet connection to create, modify, and delete any document in your Firestore instance. You might want to change that.

Related

How can I configure my firebase config to access the firebase emulator functions endpoint?

Prerequisites:
Firebase SDK: ^7.21.1
I'd like to connect my Vue.js Frontend with my local firebase functions emulator. The emulator is located at localhost:5001. I have a hard time figuring out what configuration properties I have to set to access the emulator endpoint.
Here is my current configuration:
const firebaseConfig = {
apiKey: "AIzaSyCKvB9ZluNGOP4s4r8igflwuK-9WVsoThg",
authDomain: "company-29f5c.firebaseapp.com",
databaseURL: "https://company-29f5c.firebaseio.com",
projectId: "company-bar",
storageBucket: "company-29f5c.appspot.com",
messagingSenderId: "1051704079600",
appId: "1:1051704079600:web:f99d362c43b87346",
notificationWebhookUrl: "http://localhost:5001/company-dev/us-central1/notificationsMixpanelWebhook",
cloudFunctionBaseUrl: "http://localhost:5001/company-dev/us-central1",
};
I started changing the cloudFunctionBaseUrl since it kind of was obvious for me to use this property to change the functions endpoint url. As you can see I set it to localhost:5001/.... However the url being used in my app still was calling this url:
https://us-central1-company-bar.cloudfunctions.net
I figured out that the url is being composed by the projectId property of the configuration. The cloudFunctionBaseUrl therefore is not overwriting it at all.
How can I now change the composed url
https://us-central1-company-bar.cloudfunctions.net
to
http://localhost:5001/company-dev/us-central1
I expect that there is some kind of configuration flag like enableEmulator or something like that but could not find any hint in the docs for that.
You're correct in thinking there's a function, its called useEmulator. You have to call it for each part of firebase you want to emulate as far as I'm aware.
If you want to make functions use the emulator you can do something like the following:
firebase.functions().useEmulator('localhost', 5001);
After the firebase.initializeApp call.
More information can be found on the official docs: https://firebase.google.com/docs/emulator-suite/connect_functions#

Firebase Firestore "Missing or insufficient permissions" despite open security rules

I'm trying to create a document in Firebase Firestore. I have manually added documents to it in the Web UI, but am unable to do it programmatically.
The following is a single HTML file, containing all the code, which is directly taken from the docs:
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/8.3.1/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.3.1/firebase-firestore.js"></script>
<script>
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "<REDACTED>",
authDomain: "<REDACTED>",
projectId: "<REDACTED>",
storageBucket: "<REDACTED>",
messagingSenderId: "<REDACTED>",
appId: "<REDACTED>"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
var db = firebase.firestore();
// example from the docs
db.collection("users").add({
first: "Ada",
last: "Lovelace",
born: 1815
})
.then((docRef) => {
console.log("Document written with ID: ", docRef.id);
})
.catch((error) => {
console.error("Error adding document: ", error);
});
</script>
I have redacted the config object, but it was copied directly from the Firebase config page (furthermore, I know the config is correct because in another app (not pictured), Firebase Auth works just fine).
Upon opening the above HTML page, I get the following error in the console:
Error adding document: FirebaseError: Missing or insufficient permissions.
My Firestore security rules are as follows. They should be completely open to all reads and writes:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write, update, delete, create: if true;
}
}
}
Despite the "Missing or Insufficient Permissions" error, when I go to the "Monitor Rules" tab of the Firestore Rules page, I don't see any stats for the denied requests, as if the rules didn't even get evaluated at all, despite me having ran at least 50 requests over the last 24 hours:
Running simulated Firestore requests in the Firestore Rules Playground succeeds every time as expected, whether the request is "authenticated" or not.
Please advise, I am at a loss for what else to try.
I have sidestepped solving this issue by simply creating a new project. I still don't know what was wrong. Please see the comments below my question for possible solutions.
I spoke with Google support and found you need the
firebaserules.system IAM role. Here is what I received:
Thank you for contacting Google Cloud Support. My name is Sakshi and I will be helping you with this issue.
I understand that you are getting the error [1] on the existing Google project and want to debug this error without creating a new project. Please correct me if I have misunderstood the issue.
Please note that the service account or user account you are using to authenticate Firebase project need to have ‘firebaserules.system’ role, If you don’t have this role your security rules will deny all the incoming requests. I will suggest you refer to the document [2] to know more about this in detail.
If your application is using the server client libraries or the REST or RPC APIs, please note that they bypass all Cloud Firestore security rules and instead authenticate through Google Application default credentials. Please follow this document [3] to know about Firebase security rules.
I hope the provided information is useful. Please let me know if you have any questions regarding this issue.
Regards,
Sakshi
Google Cloud Support
[1] Firebase Firestore "Missing or insufficient permissions"
[2] https://cloud.google.com/firestore/docs/security/iam#security_rule_dependency_on_iam
[3] https://firebase.google.com/docs/firestore/security/get-started

Need to connect to secondary app instances automatically with the current user in Firebase Web

I’m working with Firebase Web. I'm using multiple databases in the same project for scalability purposes. I’m not sure how to connect to a secondary database (this will be a dynamic DB) with the current authenticated user?
This is my current code:
let secondary_app = firebase.initializeApp(
{ ...config, databaseURL: secondaryDbUrl },
"secondary_app"
);
let query = firebase.database(secondary_app).ref(rtdbPath);
But this won't have the current user's authentication and hence all security rules that require auth fail.
The problem is that my secondary Db URLs are dynamic and I have to do reinitialization multiple times in the code. Should I have to sign in into the secondary app instance every time I create a secondary app through firebase.initializeApp?
Non-web SDKs seem to have a much easier approach where you are allowed to enter the Database URL directly into firebase.database() as an argument. Does a similar easier approach exist for Web SDK? Thanks for the help in advance!

How to secure Firebase RealTime Database from chrome extensions or Tampermonkey extension? [duplicate]

This question already has an answer here:
In Firebase security rules how can you stop hackers running a script for signup to your website? bare in mind I need them to be able to signup
(1 answer)
Closed 3 years ago.
Anybody who knows how to write scripts in Tampermonkey extension or how to create create extension can easily inject javascript code in webpage and access config keys. So how do you secure it?
var config = {
apiKey: "apiKey",
authDomain: "projectId.firebaseapp.com",
databaseURL: "https://databaseName.firebaseio.com",
storageBucket: "bucket.appspot.com"
};
firebase.initializeApp(config);
Right now only thing I can think of is wrap in anonymous function to avoid variable accessibility globally. which can prevent accessing variable.
It is still not secure, developer can ajax javascript file and parse data using regex, so how do you prevent it?
Another thing I thought of that is using nodejs as backend and use restapi to get data but it also exclude it being real time database. In addition I'd have to use socket.io to transfer data to client side in realtime if firebase update database in realtime in backend.
Because If anyone can inject script to access config keys can also read & write anywhere in database at his own will where read and write permission is granted.
which is a security concern. Any keys available on client is risky. so how do you prevent such attack?
This is a fairly common question. The answer is: no, a client cant write and read from everywhere in the database but only where your rules allow it.
This is exactly like REST, if you have a REST API then all your endpoints are public. What prevents mischief use are the server rules.
In this case, the database rules are in charge of securing and validating the data.
The simplest rule is user is logged in:
Items: {
.read: if auth != null,
.write: if auth != null
}
You can also have more common rules, like owner permissions
user_items: {
$uid: {
.read: if auth.uid == $uid,
.write: if auth.uid == $uid
}
}
The previous example considers a data structure where each user has its own node, but if for any reason you meant to keep it all in the same node it can be done using query rules. My recommendation would be to use the above structure, that way in the future, an admin feature can be added by denormalizing data.
The difference here is you are exposing your credentials if you take a look at them, there is nothing really private but only needed data for Firebase to match the request with your project, beyond that your project has to define the security. Please, take care of securing RTD, Firestore and Storage.

How secure is firebase with auth?

I am not sure where to begin but I recently saw 'Firebase' while searching for no server database, while it seems interesting to me, I was little worried about putting my api codes directly in the js files, which obviously can be seen through source but I have read that you can change the read/write rules and need authentication. so I no longer worried about API after reading through some pages
but the main question is:
I wanted to create an admin portal for my page, so example my admin page is located in localhost/admin/ <<< The page will simply have a login form which is to access the portal, so everything is set
var config = {
apiKey: "",
authDomain: "",
databaseURL: "",
projectId: "",
storageBucket: "",
messagingSenderId: ""
};
firebase.initializeApp(config);
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
window.location = '/portal.html'
}
else {
// Do nothing
}
});
$("#loginbtn").click(function() {
var email = $('#login-name').val();
var password = $('#login-pass').val();
firebase.auth().signInWithEmailAndPassword(email, password)
.catch(function(error) {
// Handle Errors here.
});
});
So when I log in successfully it will redirect me to that page but can someone just look through source code and then go that page manually and enter it?
Or even if I intend to build one page application and decide to change the page state after login, whatever functions i'm going to do after that, can someone still find out and inject the code ?
I'm not really expert on this but this what I was thinking before starting my project, so is there is any other way around?
If you want to add admin capabilities and you are using Firebase real-time database, you need to set some custom Firebase rules to only allow admins to access restricted data. So if a non-admin user signs in, they are unable to modify/access admin only data.
One way to do this with Firebase rules is to have a /whitelist node with uid1: "bojeil#bla.com", uid2: "puf#bla.com" for storing all whitelisted admin UIDs and then a top-level security rule for restricted admin only nodes like ".write": "auth != null && root.child('whitelist').child(auth.uid).exists()". It's fairly simple, but goes a long way.
If you are not using real-time database and building a traditional web application, you need to protect restricted admin only resources. You will need to send the Firebase ID token to your backend. You can do that by setting a session cookie with its value and making sure to update that session cookie every hour or so when the Firebase ID token is refreshed. When the cookie is sent with your request, you check for it, decode it (you can use the Firebase Admin SDKs for that) and check that the user it belongs to is an admin. If so, you can allow access, otherwise you block access. On every page, you would add an onAuthStateChanged listener. If that triggers with null, you redirect to the sign-in page. If the session cookie contains an ID token for a non-admin, you can do a HTTP redirect on your server to the user non-admin section.
tldr; you need to enforce the check on your backend by sending the Firebase ID token with the request and double checking its user has adequate privileges.

Categories