Add firestore path validation examples - #165
Conversation
There was a problem hiding this comment.
Code Review
This pull request adds guidelines and examples for validating document IDs and DocumentReference fields in Firestore security rules within both the enterprise and standard reference documentation. The review feedback suggests two key improvements to the provided code examples: enforcing a size limit on document IDs to prevent potential resource exhaustion or DoS attacks, and validating path sizes before accessing specific segments by index to avoid out-of-bounds runtime evaluation errors. All comments are constructive and provide actionable code suggestions.
| function isValidPostId(postId) { | ||
| return postId is string && | ||
| postId.matches('^[^/]+$') && | ||
| exists(/databases/$(database)/documents/posts/$(postId)); | ||
| } |
There was a problem hiding this comment.
To prevent potential resource exhaustion or DoS attacks via extremely large document IDs, it is highly recommended to enforce a realistic size limit on the postId string (e.g., postId.size() < 100), as outlined in the security guidelines of this document.
| function isValidPostId(postId) { | |
| return postId is string && | |
| postId.matches('^[^/]+$') && | |
| exists(/databases/$(database)/documents/posts/$(postId)); | |
| } | |
| function isValidPostId(postId) { | |
| return postId is string && | |
| postId.size() > 0 && | |
| postId.size() < 100 && | |
| postId.matches('^[^/]+$') && | |
| exists(/databases/$(database)/documents/posts/$(postId)); | |
| } |
There was a problem hiding this comment.
In this example, we have already confirmed that the relevant document exists, so there should be no need to impose a length restriction on the ID.
Also, document IDs already have a maximum length limit. If the intention is to validate the document ID accurately, various additional requirements would need to be checked, as shown below:
https://firebase.google.com/docs/firestore/quotas#collections_documents_and_fields
function validateID(val){
return val is string &&
val != "" &&
val.toUtf8().size() <= 1500 &&
val.matches('^[^/]*$') &&
val != "." &&
val != ".." &&
val.matches('^__.*__$') == false;
}| function isValidPostReference(postRef) { | ||
| return postRef is path && | ||
| postRef == | ||
| /databases/$(database)/documents/posts/$(postRef[4]) && | ||
| exists(postRef); | ||
| } |
There was a problem hiding this comment.
Accessing path segments by index (e.g., postRef[4]) can throw an out-of-bounds runtime evaluation error if the path has fewer segments than expected. To ensure robustness and prevent unexpected evaluation failures, validate the path size (e.g., postRef.size() == 5) before accessing specific segments.
| function isValidPostReference(postRef) { | |
| return postRef is path && | |
| postRef == | |
| /databases/$(database)/documents/posts/$(postRef[4]) && | |
| exists(postRef); | |
| } | |
| function isValidPostReference(postRef) { | |
| return postRef is path && | |
| postRef.size() == 5 && | |
| postRef == | |
| /databases/$(database)/documents/posts/$(postRef[4]) && | |
| exists(postRef); | |
| } |
There was a problem hiding this comment.
path.size() is not available. If this still needs to be done, something like string(path).split("/").size() may be necessary.
| function isValidPostId(postId) { | ||
| return postId is string && | ||
| postId.matches('^[^/]+$') && | ||
| exists(/databases/$(database)/documents/posts/$(postId)); | ||
| } |
There was a problem hiding this comment.
To prevent potential resource exhaustion or DoS attacks via extremely large document IDs, it is highly recommended to enforce a realistic size limit on the postId string (e.g., postId.size() < 100), as outlined in the security guidelines of this document.
| function isValidPostId(postId) { | |
| return postId is string && | |
| postId.matches('^[^/]+$') && | |
| exists(/databases/$(database)/documents/posts/$(postId)); | |
| } | |
| function isValidPostId(postId) { | |
| return postId is string && | |
| postId.size() > 0 && | |
| postId.size() < 100 && | |
| postId.matches('^[^/]+$') && | |
| exists(/databases/$(database)/documents/posts/$(postId)); | |
| } |
| function isValidPostReference(postRef) { | ||
| return postRef is path && | ||
| postRef == | ||
| /databases/$(database)/documents/posts/$(postRef[4]) && | ||
| exists(postRef); | ||
| } |
There was a problem hiding this comment.
Accessing path segments by index (e.g., postRef[4]) can throw an out-of-bounds runtime evaluation error if the path has fewer segments than expected. To ensure robustness and prevent unexpected evaluation failures, validate the path size (e.g., postRef.size() == 5) before accessing specific segments.
| function isValidPostReference(postRef) { | |
| return postRef is path && | |
| postRef == | |
| /databases/$(database)/documents/posts/$(postRef[4]) && | |
| exists(postRef); | |
| } | |
| function isValidPostReference(postRef) { | |
| return postRef is path && | |
| postRef.size() == 5 && | |
| postRef == | |
| /databases/$(database)/documents/posts/$(postRef[4]) && | |
| exists(postRef); | |
| } |
This PR adds document ID and DocumentReference validation examples to the
Strict Path and Relationship Scopingsection of the Firestore security rules guidance for both Standard and Enterprise editions.The examples demonstrate how to prevent path substitution by validating document IDs as single path segments and ensuring DocumentReference fields exactly match the expected path.