DOUG STEVENSON: Hey, Firebase developers.
So how do you make sure that your users can read and write
only the data in your project that they're allowed?
I'm sure you probably already know
that you can do this with Firebase security rules.
You can write security rules to protect
the data stored in Realtime Database, Cloud
Firestore, and Cloud Storage.
These rules sit between your client app and the data,
making sure that each of the reads
and writes performed by the client SDK
are allowed for the end user.
If your client app directly reads and rights data
using any of these three products,
you definitely need to think about security.
I imagine that many of you are watching today
because you got an email notification saying
that your rules aren't secure.
Hopefully, by the end of the series,
you'll be able to write rules that are good for your app.
Firebase security rules provides an expression language
that lets you choose how the end user is allowed to access
data in these products.
Note that the expression language is not
a full programming language.
And there are two varieties-- they both might
feel similar to JavaScript.
For Realtime Database, the rules are formatted using JSON.
You can see here that you identify
a node in the database, such as users, with possible wildcards
to match any child node.
Then apply conditions on that to indicate
how the data at that node may be read and written.
In this case, we're saying that anyone can read any child
node under users, but only an authenticated user
may write the child node with the same ID
as their own UID assigned by Firebase authentication.
For Cloud Firestore and Cloud Storage,
the syntax is quite different.
You have a service declaration to identify
which product is being used--
this is for Cloud Firestore-- one or more match patterns that
specify the path, and also possible wildcards of documents
or objects to protect.
Nested inside match patterns there
are allow expressions that determine
the specific conditions for accessing the document
or object.
The allow keyword requires that you also
provide a method that describes the nature of the access, which
is going to be read or write or something more granular.
This example is similar to the last one for Realtime Database,
and it's saying that all documents in the user's
collection can be read by anyone,
but only an authenticated user may write the document
with the ID that's the same as their own UID.
The expressions themselves follow
the syntax of the common expression language.
While the capabilities of both rule systems
are similar, in this series, I'm going
to spend most of the time talking about what
you can do with a common expression language used
by Firestore and Cloud Storage.
But before diving into that, it's
a good idea to wrap your head around the strategies used
to protect data.
The way I see it, there are two main categories of assertions
you will want to express in your rules.
First, there are user-based assertions,
which you can apply only if your app is also
using Firebase authentication to identify and sign in the user.
It's very common to use the unique ID of the user
to determine which things they can read and write.
You can also make use of custom claims granted to the account
in order to authorize access.
If you're not using Firebase Auth,
you won't be able to write any rules that depend on knowing
something about the user.
Authentication is a crucial part of developing a secure app,
and it's my opinion that you should integrate it
into your app as soon as possible,
even if it's just anonymous authentication,
so you can also start writing good user-based rules.
Second, there are content-based assertions,
which you can use to control access
to data based on the contents of the data itself.
So for example, imagine a Boolean field value
in a document that marks it as publicly readable by everyone.
You can use this Boolean field value
in your rules to allow access to the document.
And for write operations, you can also
examine the data about to be written in order to check it
for validity and consistency.
Ideally, you'll write rules that use a combination of these two
types of assertions.
Rules can get complex, but after everything is evaluated,
it will boil down to a single Boolean value
that either allows or rejects access.
I've said a little bit about what
you can do with security rules, but it's
also important to understand what you can't do, as well.
First, you can't change the incoming data
that's about to be written.
While you have access to the incoming data,
your rule can only allow or deny that right.
You can't fix up the data in some way.
If you need to do something like that,
consider using Cloud Functions to trigger
some code that modifies the data after the write finishes.
You also can't check to see if access is coming from your app
or website.
Firebase products are generally intended
to be accessible from anywhere there is internet access,
and there are public REST APIs, as well.
It's just not possible to control
the origin of a request using security rules.
One common misunderstanding about security rules
is that they don't act as query filters on your documents
in Firestore.
So you can't write a rule that ever
changes the outcome of a query, other than denying it entirely.
I'll say more about this in another video.
Lastly, you can't cross between products, at least
not at the time of this recording.
Cloud Firestore rules only have access to data in Firestore,
and Cloud Storage rules only have access to object metadata.
The only exception to this is the account information
provided by Firebase authentication
for the user that was signed in prior to making the request.
The security rules team is investigating the possibility
of using Firestore document data in storage rules,
but right now it's not possible.
As I said before, security rules don't provide
a full programming language.
But it is still code.
And like all code, you should test it
while you develop to make sure it works the way you expect.
It's possible to write app code that exercises your rules,
but running a special code path in your app just to test rules
isn't very convenient or efficient.
You also don't get a very helpful error message
from the client SDK in the case that an operation is denied.
So to make this easier, there are two other ways
to test your rules.
First, it's pretty easy to get started testing rules
in the Firebase console.
Realtime Database, Cloud Firestore,
and Cloud Storage all have a rules simulator
in the screen where you can edit your rules.
The simulator lets you configure a database or storage
operation, add authentication to it if you want,
and test that situation against the rules
that you see on the screen.
The console will tell you which line allowed or disallowed
access to the data.
You can test some common rules like this,
but you should know that not all situations can
be simulated in the console.
For testing more advanced rules, you
want to download the Cloud Firestore local emulator that
comes with the Firebase CLI.
With the emulator, you can write code
to set up some test documents, then
query those documents to see if they're correctly allowed
or denied by some rules.
This emulator is running the exact same code
that evaluates security rules deployed in production.
So you'll know for sure if they work correctly.
It takes some time to set up the emulator,
but this is your overall best option for serious development.
At the time of this recording, the security rules emulator
is in beta, and it's going to improve in the future.
To get started with that, check the links
in the description below.
There's a lot to know about Firebase security rules,
and this was just an introduction.
I touched on a bunch of things today,
but I'll dive into each one of them
in more detail in future videos.
So be sure to subscribe here to the Firebase channel on YouTube
to find out when the next one is available.
I'll see you then.
[MUSIC PLAYING]