Firestore Security Rules is one of the most important aspect of Firestore usage:
Security Rules
only apply to mobile and web client libraries, doesn't apply to server client libraries. Technically, user could manipulate mobile/web client, but not server code.- If you don't design the security rules properly, user can create/update/delete any data/documents. It is like configuring the security/permission of REST APIs.
Be Restrictive
Make sure all documents don't allow read/write by default.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
}
}
Even if you want to do testing, only assign permission per collection when necessary.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
match /tests/{testId} {
allow read: if true
// must sigin
allow write: if request.auth != null;
}
}
}
Check is Signin, is User, is Owner, is Admin
Check is Signin/Login.
match /tests/{testId} { function isLogin() { return request.auth != null } allow read: if true // must sigin allow write: if isLogin()}
NOTE: request.auth
is populated if client use Firebase Authentication.
Check is valid User.
function isUser() { return isLogin() && exists(/databases/$(database)/documents/users/$(request.auth.uid))}
NOTE: Assume we have a collection users
to store all valid user.
Check if valid User is active.
function isUserActive() { return isLogin() && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.active == true}
NOTE: Assume the field/property active
is used in User document to indicate active or not.
Check if User is Admin
- We can hardcode uid as Admin
- or use field/property
roles
(an array) in User document (or you can useadmin == true
)
function isAdmin() { return isLogin() && (request.auth.uid == 'QYHqCKCGSbY3qqMSliqNhR3j9QC2' || 'admin' in get(/databases/$(database)/documents/users/$(request.auth.uid)).data.roles)}
NOTE: Refer to Firestore Check Is Admin Security Rules for more alternatives.
Check is Owner
For users
collection, where {userId}
is the Document ID and could be used to check against request.auth.uid
.
match /users/{userId} {
function isOwner() {
return userId == request.auth.uid;
}
}
For other collection, we would need to check against the User ID property/field of the document.
match /comments/{commentId} {
function isOwner() {
return request.resource.data.userId == request.auth.uid;
}
}
NOTE: The above check can prevent user from imitating another user, check checking resource.data.userId
only doesn't.
Test Security Rules
Simulator
You can use the Simulator
at Firebase Console -> Database -> Rules -> Simulator
.
NOTE: Service call error. Function: [exists], Argument ...
may happend if you enable Authenticated
without Firebase UID
while using rules like exists(/databases/$(database)/documents/users/$(request.auth.uid))
NOTE: I bump into error Function not found error: Name: [get]
when using get(/databases/$(database)/documents/users/$(request.auth.uid))
while using the Simulator, and it works fine in production. This is probably a temporary bug.
Cloud Firestore Emulator
You can use Cloud Firestore Emulator.
Use Android Unit Test
Firestore Test Production Security Rules With Android Unit Test
References: