Have you ever been to a castle in Japan? Osaka Castle, a very famous castle, is said to have possessed a double moat for defense. It must have taken a lot of effort and cost to create so many moats.
Now, Firestore, like a castle, needs protection from outside forces. In Firestore, this protection is provided using Firestore Security Rules. So, how much protection should be included in Firestore Security Rules? Should it have strict data validation like the double moats of Osaka Castle?
In conclusion, in my experience, Firestore Security Rules should not include strict data validation. Now let’s consider the reasons why.
Reasons
1. The upper limit of the number of expressions to evaluate
It may surprise you to know that Firestore Security Rules sets an upper limit of 1000 on the number of expressions that can be evaluated. So if you write a lot of rigorous data validation, you may reach the limit very quickly.
In my experience, as soon as I did a rigorous data validation of an object with only 40-50 properties in total, I encountered the following error.
maximum of 1000 expressions to evaluate has been reached
So, when building a system to some extent, it is impossible to do rigorous data validation on all the data.
2. Duplicate verification
A friendly user interface shows the user what is wrong with the input in a clear way. In order to do so, data validation must be performed on the user interface side as well. If strict data validation is done on the Firestore Security Rules side, it would be a duplicate check and could cause many problems( costs, bugs, etc ).
3. Difficult to find the cause of the error
The error message for Firestore Security Rules looks like this.
FirebaseError: 7 PERMISSION_DENIED: false for ‘update’ @ L541, false for ‘update’ @ L599
Very unfriendly. The number of lines displayed only points to the location of the match statement. Since complex validation rules are usually written separately for each function, this information is not useful. The more complex data validation you write, the more you’ll get bogged down in the mire of cause-finding.
How should we view Security Rules?
It is important not to lose sight of its purpose. What are the Firestore Security Rules for? Firestore can be accessed directly by the user. So we must prevent malicious users from accessing other users’ data or destroying the database. This is the main purpose of the Firestore Security Rules!
When you think about it, isn’t the security of the data more important than the validity of the data?
Even if inconsistent data is created by a malicious user as his own data, it is almost always the malicious user himself who suffers. However, very large data can destroy the database and must be prevented by security rules. This is the difference between validity and security.
So, in most cases, your security rules should only need to check the following two things.
1. if the user has permission to access the data
2. if the user is trying to register a larger-than-expected amount of data
In fact, at first, I wrote very intricate data validation logic in my security rules. But as a result of arriving at this idea, I rewrote many data validation functions into safety check functions.
// Before
function isValidAccount(data){
return
data.size() == 2
&& 'email' in data && data.email is string
// Many expressions to validate email here
// :
// :
&& 'name' in data && data.name is string
// Many expressions to validate name here
// :
// :
}
// After
function isSafetyAccount(data){
return
data.size() == 2
&& 'email' in data && data.email is string
&& data.email.length < 100
&& 'name' in data && data.name is string
&& data.name.length < 100
}
Conclusion
More than enough is too much. Overly strict Firestore Security Rules can be harmful but not beneficial. There is no need to create a useless moat. So think carefully about the role of the rules and write appropriate ones.
I hope this article will be useful to someone. 😊
2 Responses
Nice article. You definitely should not check whether an string that represents an email is actually a valid email address in the Firestore rules. That is not why they exist.
If you want more control server side, you can disallow the user to update (or create) on Firestore, using Firestore rules. Then you can expose a Cloud Function that updates Firestore and call that Cloud Function from your code. In that function you can add all the checks that you need.
Thank you for your comments. I appreciate your advice!
I agree with your opinion that Firestore rules are not designed to check detailed data validation.
And if you want to do more complex data validation, I agree with you to use Cloud Function.
However, in my opinion, it is rare to do detailed data validation with Cloud Function, for the reasons I mentioned in my post above.
In most cases, data should be pre-checked in the UI, and if a malicious user sends malicious data directly without going through the UI, only the malicious user will be harmed. (However, fraud that affects the whole system, such as super huge data or unauthorized access to other users, should be checked.)