DEV Community

Discussion on: Why Firestore Encourages Bad Security

Collapse
gautemeekolsen profile image
Gaute Meek Olsen • Edited on

Well the flaws you mention are easily fixed with rules.

Only increment with 5 points

match /users/{id}{
  allow update: if request.resource.data.points - resource.data.points == 5 || !("points" in request.resource.data);
}
Enter fullscreen mode Exit fullscreen mode

The or operator is for when other properties than points are updated.

Prevent user from submitting the form multiple times

use batch in frontend:

const batch = db.batch();
batch.set(db.collection("form").doc("<id>"), formData);
batch.update(db.collection("users").doc("<userid>"), {has_filled_out_form: true});
batch.commit()
Enter fullscreen mode Exit fullscreen mode
match /form/{id} {
  allow write: if hasNotFilledForm() && hasFilledFormAfter();
}
function hasNotFilledForm(){
  return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.has_filled_out_form == false;
}
function hasFilledFormAfter(){
  return getAfter(/databases/$(database)/documents/users/$(request.auth.uid)).data.has_filled_out_form == true;
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

So I believe it boils down to knowing how to secure your data. I can easily create a server and a database and allow each request without writing any code for authentication, authorization, validation, etc. So the data can be both insecure and secure by using Firestore just the same as anything else.

Collapse
mysticza profile image
Chris Boik

You've nailed it on the head here.

The article fails to represent the power of security rules for validating user input and requests.

Your comparison to setting up a basic database logic layer is brilliant.

Collapse
jbis9051 profile image
Josh Brown Author

See my reply.

Collapse
jbis9051 profile image
Josh Brown Author • Edited on

Thank you for your reply! You seem to be correct that those rules would work for the examples mentioned in this article.

However, I'd like to mention a couple of points to consider.

As your application starts to grow, if you implement all the necessary security rules (validation, authentication, authorization, logical checks, "batch checking", etc.), your firestore.rules will turn into a huge and messy and unmaintainable god file, making this solution not ideal for larger applications. Also, note that there are many limits on security rules. While those limits are pretty generous, it's worth considering when building larger applications, especially when considering the next couple of points. (Admittedly, this point is not directly related to security but it is still worth considering)

Additionally, as mentioned in the article, firestore security rules do not permit you to import libraries. This means you must either copy and paste source code for libraries you want to use or build a solution yourself. The "copy and paste" method exacerbates the "god file" and limits mentioned above. You must also keep up with updates to the library. The other option, not using a library, can be very dangerous. Most developers won't be able to implement let alone maintain their own implementation of security-related libraries (hence the need for the library in the first place).


I can easily create a server and a database and allow each request without writing any code for authentication, authorization, validation, etc. So the data can be both insecure and secure by using Firestore just the same as anything else.

Yes, you are correct. Anything can be implemented securely and insecurely. I'd like to explain why it's much easier to fail to implement firebase securely than a proper backend.

Most security issues relate to a set of wrong assumptions. Not checking for authentication is an assumption that the user is who they said they are. Not checking for authorization is an assumption that the user is allowed to do what they are trying to do. Poor validation is an assumption that the data the user submits is...well..valid.

All three of these specific assumptions aren't guaranteed in both firestore security rules and a classic server environment. This is we must implement checks to confirm that the user is in fact authenticated and authorized and the input data is valid.

However, there is a very important differentiator. Code written on the backend is guaranteed to run to completion without modification. This cannot be assumed to be true on the frontend, creating yet another layer of checks that needs to be implemented in security rules.

With the batch example from before, if implemented on a proper backend one can assume that both queries WILL run in the order you specified so there is no need to check that the second query will run.

The additional security rules you posted are needed because that same assumption cannot be made about code on the frontend. As you have proven with the fairly simple example of batch queries, it is possible add security rules to check this case but doing so adds another layer where developers who often are not great at security anyway, may make wrong assumptions and implement rules that don't fully check every possible situation.

Collapse
gautemeekolsen profile image
Gaute Meek Olsen

This was a good reply with some good points I missed in the article 😊👏