Securing Firebase databases (Firestore & Realtime Database) is crucial to prevent data leaks, unauthorized modifications, and excessive billing. Here’s how to lock down access effectively.
Firestore security rules define who can read, write, or update data.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Require authentication for all collections
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
* Only authenticated users can access Firestore.
* Prevents public access (even with a direct API request).
Use custom claims to assign roles like admin, user, moderator.
On the backend, set user roles:
const admin = require("firebase-admin");
async function setAdminRole(uid) {
await admin.auth().setCustomUserClaims(uid, { role: "admin" });
console.log("Admin role assigned!");
}
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read: if request.auth.uid == userId;
}
match /admin/{document=**} {
allow read, write: if request.auth.token.role == "admin";
}
}
}
* Users can only read their own data.
* Admins have full access to specific documents.
If some data should be public (e.g., blog posts), but writes should be restricted, modify the rules:
match /posts/{postId} {
allow read: if true; // Public read access
allow write: if request.auth != null; // Only authenticated users can write
}
* Anyone can read, but only authenticated users can create posts.
Prevent malicious writes by validating data types and structure.
match /chats/{chatId}/messages/{messageId} {
allow create: if request.auth != null &&
request.resource.data.text is string &&
request.resource.data.text.size() < 500;
}
* Ensures only authenticated users can send messages, with a max of 500 characters.
For Realtime Database, define strict rules:
{
"rules": {
".read": "auth != null", // Only authenticated users can read
".write": "auth != null" // Only authenticated users can write
}
}
* Prevents public access.
* By default, Realtime Database allows anyone to read/write (dangerous!).
Ensure users can only upload their own profile pictures.
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /profile_pictures/{userId}/{fileName} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
}
}
* Users can only upload/read their own files.
Ensure only verified users can access data:
Prevent spamming by limiting writes per user.
match /messages/{messageId} {
allow create: if request.auth != null &&
request.time > request.auth.token.lastWriteTime + duration.seconds(5);
}
* Users can only send a message every 5 seconds.
* Enable it in Firebase Console > App Check > Add Provider (Play Integrity, reCAPTCHA, etc.).
| Security Measure | Firestore Rules Example |
|---|---|
| Require Authentication | allow read, write: if request.auth != null; |
| Role-Based Access (RBAC) | allow write: if request.auth.token.role == "admin"; |
| Restrict User Data Access | allow read: if request.auth.uid == userId; |
| Limit Public Access | allow read: if true; allow write: if request.auth != null; |
| Validate Input Data | request.resource.data.text is string && size() < 500; |
| Secure Storage Files | allow write: if request.auth.uid == userId; |
| Limit Request Frequency | request.time > request.auth.token.lastWriteTime + duration.seconds(5); |