How would you prevent unauthorized access to a Firebase database?

Preventing Unauthorized Access to Firebase Database

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.


1. Secure Firestore with Rules

Firestore security rules define who can read, write, or update data.

* Example: Restrict Read/Write to Authenticated Users
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).


2. Role-Based Access Control (RBAC) :

Use custom claims to assign roles like admin, user, moderator.

Step 1: Assign Roles Using Firebase Admin SDK

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!");
}
Step 2: Apply Role-Based Firestore Rules
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.


3. Restrict Public Data Access

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.


4. Validate Data Before Writing

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.


5. Secure Firebase Realtime Database

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!).


6. Restrict File Uploads in Firebase Storage

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.


7. Use Firebase Authentication

Ensure only verified users can access data:

* Enable Authentication in Firebase Console
  • Email & Password
  • Google/Facebook Sign-in
  • Phone Authentication (SMS)

8. Rate Limit Requests with Firestore Rules

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.


9. Monitor Security with Firebase App Check
  • Prevent unauthorized API calls by enabling App Check.
  • Verify client requests before processing.

* Enable it in Firebase Console > App Check > Add Provider (Play Integrity, reCAPTCHA, etc.).


Summary of Best Practices
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);