How to apply firebase storage rule so only Google cloud run API can write? - firebase

My goal is to block any write requests that don't come directly from my API in google cloud run.
I think my firebase Web API key from the general project settings could help but I can't find the right storage rule that can do this.
I found the storage rule for authenicated users etc but I don't use firebase authentication. Instead I authenticate users in the API that is hosted in google cloud run.
I think it is in this direction but please correct me if I am wrong.
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read: if true;
allow write: if request comes from my API with the Web API key;
}
}
}
sources:
https://firebase.google.com/docs/storage/security/rules-conditions
https://firebase.google.com/docs/storage/gcp-integration

There is no way to check what API key is used in the call to Cloud Storage.
But access from Cloud Run usually happens through one of the GCP SDKs/APIs and those access the project with administrative privileges and bypass your security rules altogether.
So you might as well deny all write access from untrusted clients with:
allow write: if false;

Related

Allow service account access only to a subset of a Firetime Realtime Database

I need to have some code running on a remote server with access only to a subset of my Firebase Realtime Database.
I figured I was going to be able to create a service account with access to the database, and manage it's more detailed read/write permissions using security rules. This doesn't seem to be the case.
I do not want this service account to have any other access to my Firebase project.
Here is an example of what I thought my security rules would roughly look like:
{
"rules": {
"my_restricted_data": {
"X": {
".read": "auth.my_service_account_id === 'X'",
".write": "auth.my_service_account_id === 'X'"
}
}
}
}
Looking at the Google Cloud Platform roles and permissions, I can't seem to separate Firebase Realtime Database access out from other important privileges which I do not want to grant to this service.
Is there any way I can make this work?
I am using the ruby firebase https://github.com/oscardelben/firebase-ruby
Thanks!
The library you're using wraps the Firebase REST API, which in itself can be used to access the database both as an administrative super-user and as a regular authentication user. Unfortunately the two ways to authenticate that the library offers both give administrative access to the database, without a way to specify your own UID. This means that there is no way to limit what your code can do.
I recommend filing a feature request (or a PR) on the repo to add signing in a regular user through the REST API, which will then only be allowed the access that your rules have set for it.

Firebase Security Open Access

My android wallpaper app is connected to Firebase Cloud Firestore. It doesn't have any user authentication because I want the user to be able to use it without fuss. To do this, it must be in open access, meaning, the user is allowed to read and write. This is dangerous as he can also edit and modify the data if he knows the project id. The project id is visible in the url of the app so this is not really a good choice. Closed access is also not an option for obvious reasons.
Is there anything I can do to protect my data without need of a user authentication? I would love to see the code needed for the Cloud Firestore and Storage to protect the data. I want the user to read only and I, as the owner, should be the only one who could write. Please refer to the images attached. Thanks a lot for taking time to answer my questions.
My data structure in Firebase Cloud Firestore:
Securing your data with Security Rules
Firebase Cloud Firestore, Firebase Realtime Database and Firebase Cloud Storage are secured by their own Security Rules. They provide access control and data validation in a simple yet expressive format and allow you to control access to documents and collections in your database.
To build user-based and role-based access systems that keep your users' data safe, you need to use Firebase Authentication with Cloud Firestore Security Rules.
Your specific use case
I assume that you store your data in Firebase Cloud Firestore and the wallpapers in Firebase Cloud Storage. The user then gets a document with a link to download a wallpaper and maybe also can upload their own wallpapers to the database.
The dangers of an open database
As you mentioned allowing all reads and writes to your database in a production app is very dangerous. Obviously, anyone with your database reference will be able to read or write data to your database. Unauthorized users could destroy your backend and there are also possibilities that costs could increase exponentially. Therefore this is not recommended. There always should be some mechanisms preventing these scenarios.
Recommendation: Using anonymous authentication first and connect later with existing Identity Providers
I recommend that you use Firebase Authentication to create and use temporary anonymous accounts to authenticate with Firebase. These temporary anonymous accounts can be used to allow users who haven't yet signed up to your app to work with data protected by security rules while not being in the way of your user experience. If an anonymous user later decides to sign up to your app, you can link their sign-in credentials to the anonymous account so that they can continue to work with their protected data in future sessions.
You could also enable Google-Sign-In, Facebook Login, Twitter, GitHub, Microsoft, Yahoo, etc. to let users authenticate in a very fast and easy way without compromising on a security standpoint if using regular password authentication is not what you want (from a UX standpoint). FirebaseUI makes it really easy to add these to your existing app. Check out the official documentation on this topic.
Implementing Cloud Firestore Security Rules
The official documentation on this is really great on how to get started with Cloud Firestore Security Rules.
However these security rules could work for you:
Allow read access to all users to the root (Not recommended because this can create huge costs in production). Users don't have write (create, update, delete) access. In this case you can edit your data via the Firebase Console. Choose either option 1 or option 2 for your project.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Option 1: Matches any document in the 'root' collection.
match /root/{rumiXYZ} {
allow read: if true;
allow write: if false;
}
// Option 2: Matches any document in the 'root' collection or subcollections.
match /root/{document=**} {
allow read: if true;
allow write: if false;
}
}
}
The {document=**} path in the rules above can be used to match any document in the collection/subcollections or in the entire database. This should however not be necessary for your use case. Continue on to the guide for structuring security rules to learn how to match specific data paths and work with hierarchical data.
Don't forget to secure your Firebase Cloud Storage too!

Do firebase storage rules override cloud storage permissions?

I have the following rules in my bucket:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read;
}
}
}
This says to me that public can read - but they can't. Checking on the google cloud storage UI, there is no 'public url'.
So a couple of questions:
Does firebase give a different URL for accessing the file which will issue permissions based on the above rule configuration?
There is a firebase-adminsdk service account in GCS bucket permissions - is that what firebase uses to access the bucket?
Which credentials overwrite each other?
​
Cloud Storage access permissions and Firebase's Storage rules are unrelated.
Firebase's Storage rules apply to users who access the data in the bucket through a Firebase SDK. In addition Firebase can generate a so-called download URL, which gives everyone who has that URL read-only access to that file.
Cloud Storage access permissions apply to users accessing the data in the bucket through a Cloud API. The Cloud Storage SDKs and APIs can also generate so-called signed URLs, which serve a similar role to the download URLs mentioned above.
Firebase security rules only affect direct access from web and mobile client apps when using the Firebase SDK, especially when the user is authenticated with Firebase Auth (as the user's account token is made available during the evaluation of rules).
Rule do not affect the way service accounts work, or other forms of public access that depend on Cloud Storage ACLs. Those are determined by their own permission systems. Those other systems don't also don't affect Firebase client access at all.

Firebase storage: check if user is admin

I have a folder in Firebase storage that only the admin service account should be able to write to. (More particularly, that admin service account will only write to the storage from a cloud function).
I'd like to figure out how to create a rule that prevents any other user from writing to the storage bucket. Does anyone know how one can accomplish this goal?
I thought I could create a rule that forbid writing unless the writing agent's uid matched the admin uid, but I haven't been able to find the admin uid yet. I tried logging into my service account like so:
import firebase_admin, os
from firebase_admin import credentials, initialize_app
if not len(firebase_admin._apps):
cert = os.path.join('src', 'secrets', 'service-account.json')
initialize_app(credentials.Certificate(cert), {
'databaseURL': 'https://womp.firebaseio.com/',
'storageBucket': 'womp.appspot.com/',
})
then digging through the firebase_admin._apps[0] object to see if I could dig out a uid for the user, but no dice.
If others know how to create a rule that prevents any but admin users from writing to a storage instance, I'd be grateful for any insights they can offer!
It's not possible to limit access to service account using security rules. Service accounts always bypass security rules.
Once you start working with service accounts, their access is controlled by Google Cloud IAM, which is completely different. You can use IAM to limit which service accounts are allow to access a bucket, and that's going to operate completely independently of whatever security rules you write for end users going through the Firebase SDK.
If you don't want any users to write directly to a bucket, and only allow service account, the security rules for the bucket should simply reject all access.
match /{document=**} {
allow read, write: if false;
}

Trying to make app secure with API key, but it isn't being used

I've created a web application that displays data from my cloud firestore. I'm about to release it to the public, but I don't want just anyone to be able to read/write to my database.
I have currently restricted my API key to only allow requests from my website's url, but it doesn't seem to be doing anything. I've even deleted it from the app entirely and it is still able to access the database.
Is there a rule I need to set up in my firestore to make it require an API key? I've googled plenty of things, but all I can find are articles on why it's ok to have your key be available to the public.
It's not possible to restrict access to Firestore based on some plaintext API key or web site domain. If you're publishing an app that provides direct access to Cloud Firestore (or Cloud Storage, or Realtime Database), the only way to secure it is with a combination of Firebase Authentication and security rules. The security rules allow you to express who can read and write which collections and document.
If you aren't using Firebase Authentication, and your default security rules allow universal read/write access, then anyone with an internet connection will be able to read and write every document.
A slight variation on Doug's excellent answer is to allow all users to write to specific documents that pre-exist and that have impossible to guess names. These document names then essentially become your own API keys, that you share (out of band) with the users of your app.
The security rules for this can be as simple as:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow create: if false;
allow update: if exists(resource['__name__']);
allow get: if true;
allow list: if false;
}
}
}
So: anyone can get/update any existing document that they know the name of, but they can't create a document, nor get a list of all documents.
This prevents the need for using Firebase Authentication. On the other hand it means you can't lock down access on a per user basis. Any user that somehow gets access to the document name, can now read/write it at will.

Resources