DEV Community

Cover image for The Complete Guide to Firebase Security Rules: Why They Matter and how to Write Them
Codexlancers
Codexlancers

Posted on

The Complete Guide to Firebase Security Rules: Why They Matter and how to Write Them

When building modern web and mobile applications, backend security is often the most stressful piece of the puzzle. Traditional architectures require you to spin up a custom server, write middleware, and handle authentication routing just to protect a single database row.

Firebase flips this model on its head. By allowing client applications to talk directly to backend services like Firestore and Cloud Storage, it drastically speeds up development. But this architectural shift introduces a critical question: If the client can touch the database directly, what stops a user from modifying someone else's data?

The answer is Firebase Security Rules. Let's break down what they are, why they are non-negotiable for production apps, and exactly how to implement them across different Firebase services.

What is Firebase Security, and Why Is It Crucial?

Firebase Security Rules are server-side access control configurations that sit directly between your client app and your cloud data. They act as an invisible, structural shield. Every single incoming read or write request is intercepted by Firebase and evaluated against these rules. If the request doesn't meet your criteria, Firebase rejects it entirely.

Why You Can't Ignore Them

  1. The Client is Insecure: No matter how secure your Flutter, React, or native mobile code feels, an advanced user can decompile your app package, extract your Firebase configuration keys, and make direct calls to your endpoints via tools like Postman or custom scripts.

  2. Data Integrity: Security rules do more than just check user identity - they validate schemas. They ensure strings aren't passed into number fields, field lengths don't exceed limits, and mandatory fields aren't missing.

  3. Billing Protection: Leaving your database wide open allows malicious actors or rogue bots to scrape your data continuously, executing millions of reads that can instantly maximize your billing tier.

Which Firebase Services Use Security Rules?

Firebase applies individual security rule structures across three core backend services:

  • Cloud Firestore: Flexible, scalable NoSQL cloud database.
  • Realtime Database: Original, low-latency document-store database.
  • Cloud Storage: Built for storing and serving user-generated content like images, audio, and videos.

Let's look at two practical, real-world examples for each service to see how these rules look in action.

1. Cloud Firestore Examples

Firestore rules leverage granular path matching and custom conditions to control access down to specific document fields.

Example A: User-Owned Data Only (CRUD Isolation)

In a social or note-taking application, a user should only be able to view, edit, or delete notes that they created. This rule matches the user's logged-in unique ID (request.auth.uid) against the document's path variable.

service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId}/notes/{noteId} {
      // Allow access only if the authenticated user matches the path ID
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Example B: Strict Content and Type Validation

If you run an e-commerce platform or inventory app, any authenticated user can browse products, but only incoming data that passes formatting checks can be added to the catalog.

service cloud.firestore {
  match /databases/{database}/documents {
    match /products/{productId} {
      // Anyone can read product details
      allow read: if true;

      // Enforce data integrity during creation
      allow create: if request.auth != null 
        && request.resource.data.price is int 
        && request.resource.data.price > 0
        && request.resource.data.title.size() <= 50;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
  • request.resource.data: Points to the map data of the document as it will look if the write succeeds.

2. Realtime Database Examples

Realtime Database rules use a unique, hierarchical JSON structure rather than matching specific service paths.

Example A: Chat Room - Read Allowed, Write Restrained

In a global chat application, any user who is logged in should be able to read the history of a chat room, but they can only post messages that carry their own UID.

{
  "rules": {
    "public_chats": {
      "$roomId": {
        ".read": "auth != null",
        "messages": {
          "$messageId": {
            ".write": "auth != null && newData.child('senderId').val() === auth.uid"
          }
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Example B: Preventing Data Overwrites (Immutable Records)

For critical logging data, financial audits, or transaction histories, you want users to be able to submit a log once, but prevent anyone from editing or deleting it later.

{
  "rules": {
    "transaction_logs": {
      "$logId": {
        ".read": "auth != null",
        // Allow creation only if data doesn't exist yet; prevent modifications
        ".write": "auth != null && !data.exists() && newData.exists()"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

3. Cloud Storage Examples

Firestore security parameters do not automatically safeguard your file assets. Cloud Storage handles rules separately to regulate asset uploads and size caps.

Example A: Restricting Upload File Sizes and MIME Types

To keep your storage costs under control and prevent bad actors from executing Denial of Service (DoS) attacks via massive files, you can restrict uploads to specific image file formats under 5MB.

service firebase.storage {
  match /b/{bucket}/o {
    match /profile_pictures/{userId}/{allPaths=**} {
      // Profiles are publicly readable
      allow read: if true;

      // Uploads must belong to the user, be an image, and be under 5MB
      allow write: if request.auth != null && request.auth.uid == userId
                   && request.resource.size < 5 * 1024 * 1024
                   && request.resource.contentType.matches('image/.*');
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Example B: Private Business Document Multi-User Access

Imagine an app where multiple users belong to an organization account. They need access to a shared bucket of secure PDFs, while outside users are completely blocked.

service firebase.storage {
  match /b/{bucket}/o {
    match /organizations/{orgId}/documents/{docId} {
      // Allow access if the user's custom auth token contains the matching organization ID
      allow read, write: if request.auth != null 
                         && request.auth.token.organizationId == orgId;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Best Practices for Writing Firebase Security Rules

As your application grows, security rules can quickly become difficult to manage. Following a few best practices can help keep your Firebase project secure and maintainable.

Start With Deny-By-Default

Instead of allowing broad access and restricting it later, begin with restrictive rules and explicitly grant permissions where needed. This reduces the risk of accidentally exposing sensitive data.

Never Trust Client-Side Validation

Validating forms in your app improves user experience, but it does not provide security. Attackers can bypass your UI entirely and send requests directly to Firebase. Always enforce critical validations in your security rules.

Follow the Principle of Least Privilege

Users should only have access to the data and operations they absolutely need. Avoid granting collection-wide write access when document-level access is sufficient.

Use Custom Claims for Roles

For applications with administrators, moderators, or organization-based permissions, use Firebase Authentication custom claims instead of storing roles directly in client-accessible documents.

Test Rules Before Deployment

Firebase provides the Emulator Suite to test security rules locally. Verify both successful and failed requests to ensure your rules behave exactly as expected.

Keep Rules Under Version Control

Treat security rules like application code. Review changes carefully, track them in Git, and include them in your deployment process.

Conclusion

Writing Firebase Security Rules can feel like extra overhead when you are trying to ship features quickly, but they are the literal foundation of your app's security model. Treat your security rules with the same respect as your frontend architecture - write them early, test them using the local Firebase Emulator Suite, and track them under version control.

Top comments (0)