Realtime Database security rules in Firebase - Time & Space Complexity
When using Realtime Database security rules, it is important to understand how the time to check permissions grows as your data grows.
We want to know how the number of rule checks changes when more data is accessed or written.
Analyze the time complexity of security rule checks for reading a list of items.
{
"rules": {
"items": {
"$itemId": {
".read": "auth != null",
".write": "auth != null && data.child('owner').val() == auth.uid"
}
}
}
}
This rule allows authenticated users to read any item and write only if they own it.
When a client reads multiple items, the database checks the read rule for each item.
- Primary operation: Evaluating the read rule for each item requested.
- How many times: Once per item in the list being read.
Each additional item read requires one more rule check, so the total checks grow as the number of items grows.
| Input Size (n) | Approx. API Calls/Operations |
|---|---|
| 10 | 10 rule checks |
| 100 | 100 rule checks |
| 1000 | 1000 rule checks |
Pattern observation: The number of rule checks increases directly with the number of items read.
Time Complexity: O(n)
This means the time to check security rules grows linearly with the number of items accessed.
[X] Wrong: "Security rules are checked once per request, no matter how many items are read."
[OK] Correct: Each item read triggers its own rule check, so more items mean more checks.
Understanding how security rule checks scale helps you design efficient and secure database access patterns.
"What if the read rule included a condition that checks a parent node instead of each item? How would the time complexity change?"
Practice
Solution
Step 1: Understand the role of security rules
Security rules are designed to protect data by controlling access permissions.Step 2: Identify the correct purpose
They do not affect speed, backups, or indexing but focus on access control.Final Answer:
To control who can read or write data in the database -> Option AQuick Check:
Access control = To control who can read or write data [OK]
- Confusing security rules with database performance features
- Thinking rules create backups automatically
- Assuming rules manage indexing
Solution
Step 1: Recall the correct auth check syntax
Firebase usesauth != nullto check if a user is signed in.Step 2: Compare options
"read": "auth != null" uses the correct syntax. Options A and B use wrong variables or conditions. "read": "auth === true" uses invalid comparison.Final Answer:
"read": "auth != null" -> Option BQuick Check:
Authenticated check = auth != null [OK]
- Using 'user' instead of 'auth'
- Checking auth == null instead of auth != null
- Using triple equals (===) which is invalid in rules
{
"rules": {
"messages": {
".write": "auth != null"
}
}
}Solution
Step 1: Analyze the write condition
The rule states.write": "auth != null", meaning only authenticated users can write.Step 2: Consider unauthenticated user case
If the user is not authenticated,auth == null, so write is denied.Final Answer:
The write will be allowed only if the user is authenticated -> Option AQuick Check:
auth != null allows writes only for signed-in users [OK]
- Thinking unauthenticated users can write
- Confusing read and write rules
- Assuming syntax error without checking code
{
"rules": {
"users": {
".read": "auth != null",
".write": "auth.id == auth.uid"
}
}
}Solution
Step 1: Check the write rule syntax
The write rule usesauth.id, but the correct property isauth.uid.Step 2: Verify other parts
The read rule is correct to allow authenticated users. The braces are balanced. The write rule should compareauth.uid.Final Answer:
The write rule uses 'auth.id' which is incorrect -> Option DQuick Check:
Use auth.uid, not auth.id [OK]
- Using wrong property name 'auth.id'
- Changing read rule incorrectly
- Assuming syntax error due to braces
Solution
Step 1: Understand the requirement
Users should only access their own data under /users/{userId}.Step 2: Check each option
{ "rules": { "users": { "$userId": { ".read": "auth != null && auth.uid == $userId", ".write": "auth != null && auth.uid == $userId" } } } } correctly checks that the authenticated user's ID matches the path variable $userId for both read and write. { "rules": { "users": { "$userId": { ".read": "auth != null", ".write": "auth != null" } } } } allows any authenticated user to access all profiles. { "rules": { "users": { ".read": "auth.uid == $userId", ".write": "auth.uid == $userId" } } } uses $userId outside its scope. { "rules": { "users": { "$userId": { ".read": "true", ".write": "true" } } } } allows everyone access.Final Answer:
{ "rules": { "users": { "$userId": { ".read": "auth != null && auth.uid == $userId", ".write": "auth != null && auth.uid == $userId" } } } } -> Option CQuick Check:
auth.uid == $userId restricts access to own data [OK]
- Allowing all authenticated users access to all profiles
- Using variables outside their scope
- Setting rules to true allowing public access
Ready to prove it?
Pass the test and this pattern moves unknown
