Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firestore Security rules without Authentification

I store data in a Cloud Firestore database. Users in my app don´t need to create an account to get data and they can also write data without to login.

Google reminds me every few days that my database is insecure and can be abused by anyone. How can I improve it without accessing Auth variables?

My firebase rules

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write;
    }
  }
}

Is there a way to make my database more secure without using authentication?

The logic of my app:

My database contains surnames and their origin. If someone enters a name, he gets the origin back from the database. Example: "Doe" -> "Mexican". If the last name does not exist in my database, I call an API and save the value to my database. Every user needs both read and write permission.

What can I do here?

like image 588
asored Avatar asked Oct 18 '19 14:10

asored


People also ask

Can I use firestore without authentication?

To be honest, without Firebase Authentication, it's not possible to accept writes to a database without Authentication and also avoid abuse, since anyone could write anything from anywhere on the internet.

How do I set firestore security rules?

Cloud Firestore provides a rules simulator that you can use to test your ruleset. You can access the simulator from the Rules tab in the Cloud Firestore section of the Firebase console. The rules simulator lets you simulate authenticated and unauthenticated reads, writes, and deletes.

What is firestore security rules?

Cloud Firestore Security Rules allow you to control access to documents and collections in your database. The flexible rules syntax allows you to create rules that match anything, from all writes to the entire database to operations on a specific document.


2 Answers

Since the operation that you require writes for is limited (only inserting new items) you have some options:

  • You could deny writes to end user clients, and instead send a request to a cloud function that does exactly the operation you need (after verifying the input, or any other checks you might want, rate limiting, etc). Cloud functions ignore the security rules as they run with administrative access.

Here is a sample node function that performs a write to a realtime database, and it succeeds when both read and write are false in the security rules (your associated package.json obviously needs to depend on firebase-admin and firebase-functions):

const functions = require('firebase-functions');

// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin');
admin.initializeApp();

let db = admin.firestore();

// This pushes the "text" parameter into the RDB path /messages/(hash)/original
exports.addMessage = functions.https.onRequest(async (req, res) => {
    // Grab the text parameter.
    const original = req.query.text;
    // Push the new message into the Realtime Database using the Firebase Admin SDK.
    const snapshot = await admin.database().ref('/messages').push({original: original});
    // Respond to the user (could also be a redirect).
    res.send('got it: ' + snapshot.ref.toString());
  });

You may want to read about how the firebase admin SDK does access control but within a cloud function you should have admin rights by default.

  • Using the rules language you could only allow create operations. This removes the ability of the client to update or delete existing data. This isn't quite as secure as the prior method, but might be ok for you:
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read;
      allow create;
    }
  }
}

Also, note this works for firestore (which you are using) but not for realtime database.

Obviously both of these methods could be in some way abused to write lots of data into your database, though the former gives you a lot more control about what is allowed (e.g. you could prevent more than N entries, or more than Y bytes per entry). The later still lets anyone create whatever they want.

like image 58
robsiemb Avatar answered Dec 13 '22 18:12

robsiemb


Check out this documentation. https://firebase.google.com/docs/firestore/security/rules-structure. Configure the writing of unauthenticated users only in the collections you specify.

service cloud.firestore {
  match /databases/{database}/documents {

    // authentication required
    function issignedin() {
      return request.auth != null;
    }

    // authentication not required
    function notAuthenticated() {
      return request.auth == null;
    }

    // A read rule can be divided into get and list rules
    match /cities/{city} {
      // Applies to single document read requests
      allow get: if notAuthenticated();

      // Applies to queries and collection read requests
      allow list: if notAuthenticated();
    }

    // A write rule can be divided into create, update, and delete rules
    match /cities/{city} {
      // Applies to writes to nonexistent documents
      allow create: if notAuthenticated();

      // Applies to writes to existing documents
      allow update: if notAuthenticated();

      // Applies to delete operations
      allow delete: if notAuthenticated();
    }
  }
}

as a consideration, this will be insecure if the calling API allows indiscriminate writing. Note: If the API you are referring to is the only one you can write, you must configure only the reading as public

service cloud.firestore {
  match /databases/{database}/documents {

    // authentication required
    function issignedin() {
      return request.auth != null;
    }

    // authentication not required
    function notAuthenticated() {
      return request.auth == null;
    }

    // A read rule can be divided into get and list rules
    match /cities/{city} {
      // Applies to single document read requests
      allow get: if notAuthenticated();

      // Applies to queries and collection read requests
      allow list: if notAuthenticated();
    }

    // A write rule can be divided into create, update, and delete rules
    match /cities/{city} {
      // Applies to writes to nonexistent documents
      allow create: if issignedin();

      // Applies to writes to existing documents
      allow update: if issignedin();

      // Applies to delete operations
      allow delete: if issignedin();
    }
  }
}

like image 27
yson Avatar answered Dec 13 '22 16:12

yson