Firebase Security Rules
Libraries and Versions
Last Reviewed: Sep 13, 2020
We are preparing our app to go public, so the first thing we want to do is to update our security rules on the server, we do not want people connecting to the app and having access to someone else's data.
Firestore Security
With the Cloud Firestore Security Rules, we can focus on building a great user experience, without having to manage infrastructure or write server-side authentication and authorization code.
The idea is to authenticate users through Firebase Authentication and set up rules to determine who has access to data stored in Cloud Firestore.
We can find our security rules in the Rules tab in the Cloud Firestore section of the Firebase Console.
To start securing our database we need to understand how the security rules work, let's take a look at the default ones that come when we create the app.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
}
}
The security rules work matching documents in the database, they have two
permissions, read
and write
which are both false by default, meaning, no one
has access to the database.
To start working with them, we tell them to allow all read/write operations, since we're going to be in development mode:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write;
}
}
}
The =**
symbol is a cascade operator, rules don't cascade by default.
So if we set up a read/write rule for the document users/{userId}
but don't
set up read/write rules for users/{userId}/tasks/{taskId}
no one will have
access to the taskId
documents.
When we use the =**
operator, we're telling Firestore rules that if the user
matches the condition to read that document, they should be able to read all the
sub-collections and documents below that tree.
The brackets mean we're using a wild-card, for example, if I have a collection
called users
that has the documents for each user's profile, I'd only want the
profile owner to be able to have read/write access.
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, write: if request.auth.uid == userId;
}
}
}
Notice how we're getting the user's uid
from the request
object. When
working with Firestore rules, we have two available objects.
The request
object has information about the request made, such as the
authenticated user: request.auth
, and the time the request was made:
request.time
.
The resource
object is THE Firestore document we're accessing. For example,
let's say we have public and private profiles, each profile has a flag called
public
and it's either set to true
or false
.
The resource
object gives us access to that flag:
service cloud.firestore {
match /databases/{database}/documents {
match /myCollection/myDocument {
allow read: if resource.data.public == true;
}
}
}
In that case, people will only be able to read profiles marked as public
.
Storage Security
We should also set up rules for Firebase Storage, that way we can protect our users' files.
We will need to go to: console.firebase.google.com/project/YOURAPPGOESHERE/storage/rules
Identifying our user is only part of security. Once we know who they are, we need a way to control their access to files in Cloud Storage.
Cloud Storage lets we specify per file and per path authorization rules that live on our servers and determine access to the files in our app. For example, the default Storage Security Rules require Firebase Authentication to perform any read or write operations on all data:
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
Data Validation
Firebase Security Rules for Cloud Storage can also be used for data validation,
including validating file name and path as well as file metadata properties such
as contentType
and size
:
service firebase.storage {
match /b/{bucket}/o {
match /images/{imageId} {
// Only allow uploads of any image file that's less than 5MB
allow write: if request.resource.size < 5 * 1024 * 1024
&& request.resource.contentType.matches('image/.*');
}
}
}
This article is extracted from The Firebase Security Guide, which is a complete course on Firebase Security covering authentication, Firestore, Cloud Storage, and Cloud Functions.
You can enroll here.