What do these default security rules for the Firebase Realtime Database mean?
I've created a new project on Firebase, and created a Realtime Database in there. When asked about the security rules for my database, I selected to Start in test mode.
Now the security rules of my database in the Firebase console show up as:
{
"rules": {
".read": "now < 1622790000000", // 2021-6-4
".write": "now < 1622790000000", // 2021-6-4
}
}
What do these rules mean? And how can I change them to be more secure?
These default test mode rules are a simple catch-all that allows everyone in the world to read from and write to your database until a given date.
Let's break the rules down to see exactly how they work:
-
The
".read"
and".write"
nodes immediately under"rules"
determine who can read/write the data in the entire database. -
The
now
variable is automatically set by Firebase to be the current time on the server. This value is in milliseconds since the epoch, which is the recommended value to also store timestamps in Firebase. -
The
1622790000000
value in the rules is the timestamp of some point in the future. Let's see what this value is in a more readable date format:console.log(new Date(1622790000000))
"2021-06-04T07:00:00.000Z"
So anyone can read of write all data in our database until June 4th, 2021. After that date nobody can access the data anymore with the client-side SDKs. The Firebase Admin SDKs bypass these rules altogether, so they are not affected.
Can I extend the time period?
You may have gotten a message like this from Firebase:
You chose to start developing in Test Mode, which leaves your Realtime Database instance completely open to the Internet. Because this choice makes your app vulnerable to attackers, your database security rules were configured to stop allowing requests after the first 30 days. In 5 day(s), all client requests to your Realtime Database instance will be denied.
This message means that access to your data is about to expire, due to timestamp that is in your security rules.
It's actually pretty easy to extend the test mode to another deadline. All you need to do is change that 1622790000000
value. For example, for extend it to July 4th, I can set the value to 1625382000000
.
To determine the value to use, I run this tiny JavaScript snippet:
console.log(new Date("2021-07-04T07:00:00.000Z").getTime())
Here's another tool to calculate these values.
By using 1625382000000
we've extended test mode for a month and everyone can read/write the entire database until July 4, 2021.
How can I better protect the data?
At some point you should come up with a better way to protect your (user's) data than just opening it until a specific date. I typically do this right when I start a project, but it's also fine if you start it a bit later.
The important thing is that you should treat the server-side security rules the same as the client-side source code of your app.
I develop my code and rules in tandem. So:
-
I start with a fully closed off database, since there is no code yet that needs access to any data.
-
I add some data manually to the database, and write code to read it. At this point, I write security rules that only allow read-access to that specific data. So it may be
".read": true
, but it'll be much deeper in my JSON structure. Even such simple rules will already block many bad actors. -
The first time I want the app to write to the database is also when I add authentication. Typically I start with anonymous auth, since it does not require me to enter any credentials.
I then include the hard-coded UID in my security rules, to ensure only I can write data. You'll often still find this top-level
".write": "auth.uid === 'hardcodedUidOfPufsAnonymousUser'"
in my rules much later, after I added proper data ownership.When using Firestore I sometimes evolve that as explained here: User conflict when using same Auth method for Admin and Normal users | Firebase Auth
-
At any point when I add (typically lists of) data, I think through who "owns" this data, and who can read it. I then expand my rules to allow exactly that access, and nothing more.
This need to update my security rules as I write code slows down the pace at which I code, but I'll gladly do it anyway. Keeping the data in my database secure at every step, allows me to give people access to the app/database with confidence. I recommend you do the same.
For more information, I recommend reading:
- The Firebase documentation on security rules, which contains examples of these common use-cases:
- Content-owner only access
- Public read, private write access
- Attribute and role based access
- All authenticated users can read/write all datsa