An issue with preventing users from changing specific document fields in Firestore
I'm using firebase in my Android project, I have a users collection in the Cloud Firestore database, users can only update some fields, but can read all, I know it is not possible to protect a subset of a document from being updated, and security rules can be applied only to the entire document, so I searched about this and the only solution I found is to make a sub-collection inside the user document and create a new document inside this sub-collection and finally put fields I want to protect in there, then I can easily secure this document applying this code in security rules section:
match /users/userId/securedData/securedData
allow write: if false;
allow read: if true;
So now no one can write these fields, but anyone can read, and this is exactly what I want, but later I found that I need to query users based on fields inside the sub-collection, what is known as a collection group query which is not supported at the moment, so I ended up with two solutions:
- Retrieve all users and filter them at the client side, but this will increase the number of the document reads because I'm querying all users collection documents + an extra sub-collection document read for each user to get the needed field for filtering users.
Instead of making a sub-collection inside user document and incurring these problems, just keep all fields in the top level document(user document), allowing users to update any field.
match /users/userId
allow update, read: if true;
allow create, remove: if false;But make an (onUpdate) cloud function to listen on user document update and
detect changes in fields which aren't allowed to be modified by the user, so
if the user tried to change these fields I can detect this and return modified fields to their previous values like this:export const updateUser = functions.firestore
.document('users/userId')
.onUpdate((change, context) =>
const previousValue = change.before.data().securedField;
const newValue = change.after.data().securedField;
if (previousValue !== newValue)
return db.collection('users')
.doc(context.params.userId)
.update( securedField: previousValue );
);
Is the second solution secure? which is the best solution for this? or any other solutions?
firebase google-cloud-firestore google-cloud-functions firebase-security-rules
add a comment |
I'm using firebase in my Android project, I have a users collection in the Cloud Firestore database, users can only update some fields, but can read all, I know it is not possible to protect a subset of a document from being updated, and security rules can be applied only to the entire document, so I searched about this and the only solution I found is to make a sub-collection inside the user document and create a new document inside this sub-collection and finally put fields I want to protect in there, then I can easily secure this document applying this code in security rules section:
match /users/userId/securedData/securedData
allow write: if false;
allow read: if true;
So now no one can write these fields, but anyone can read, and this is exactly what I want, but later I found that I need to query users based on fields inside the sub-collection, what is known as a collection group query which is not supported at the moment, so I ended up with two solutions:
- Retrieve all users and filter them at the client side, but this will increase the number of the document reads because I'm querying all users collection documents + an extra sub-collection document read for each user to get the needed field for filtering users.
Instead of making a sub-collection inside user document and incurring these problems, just keep all fields in the top level document(user document), allowing users to update any field.
match /users/userId
allow update, read: if true;
allow create, remove: if false;But make an (onUpdate) cloud function to listen on user document update and
detect changes in fields which aren't allowed to be modified by the user, so
if the user tried to change these fields I can detect this and return modified fields to their previous values like this:export const updateUser = functions.firestore
.document('users/userId')
.onUpdate((change, context) =>
const previousValue = change.before.data().securedField;
const newValue = change.after.data().securedField;
if (previousValue !== newValue)
return db.collection('users')
.doc(context.params.userId)
.update( securedField: previousValue );
);
Is the second solution secure? which is the best solution for this? or any other solutions?
firebase google-cloud-firestore google-cloud-functions firebase-security-rules
add a comment |
I'm using firebase in my Android project, I have a users collection in the Cloud Firestore database, users can only update some fields, but can read all, I know it is not possible to protect a subset of a document from being updated, and security rules can be applied only to the entire document, so I searched about this and the only solution I found is to make a sub-collection inside the user document and create a new document inside this sub-collection and finally put fields I want to protect in there, then I can easily secure this document applying this code in security rules section:
match /users/userId/securedData/securedData
allow write: if false;
allow read: if true;
So now no one can write these fields, but anyone can read, and this is exactly what I want, but later I found that I need to query users based on fields inside the sub-collection, what is known as a collection group query which is not supported at the moment, so I ended up with two solutions:
- Retrieve all users and filter them at the client side, but this will increase the number of the document reads because I'm querying all users collection documents + an extra sub-collection document read for each user to get the needed field for filtering users.
Instead of making a sub-collection inside user document and incurring these problems, just keep all fields in the top level document(user document), allowing users to update any field.
match /users/userId
allow update, read: if true;
allow create, remove: if false;But make an (onUpdate) cloud function to listen on user document update and
detect changes in fields which aren't allowed to be modified by the user, so
if the user tried to change these fields I can detect this and return modified fields to their previous values like this:export const updateUser = functions.firestore
.document('users/userId')
.onUpdate((change, context) =>
const previousValue = change.before.data().securedField;
const newValue = change.after.data().securedField;
if (previousValue !== newValue)
return db.collection('users')
.doc(context.params.userId)
.update( securedField: previousValue );
);
Is the second solution secure? which is the best solution for this? or any other solutions?
firebase google-cloud-firestore google-cloud-functions firebase-security-rules
I'm using firebase in my Android project, I have a users collection in the Cloud Firestore database, users can only update some fields, but can read all, I know it is not possible to protect a subset of a document from being updated, and security rules can be applied only to the entire document, so I searched about this and the only solution I found is to make a sub-collection inside the user document and create a new document inside this sub-collection and finally put fields I want to protect in there, then I can easily secure this document applying this code in security rules section:
match /users/userId/securedData/securedData
allow write: if false;
allow read: if true;
So now no one can write these fields, but anyone can read, and this is exactly what I want, but later I found that I need to query users based on fields inside the sub-collection, what is known as a collection group query which is not supported at the moment, so I ended up with two solutions:
- Retrieve all users and filter them at the client side, but this will increase the number of the document reads because I'm querying all users collection documents + an extra sub-collection document read for each user to get the needed field for filtering users.
Instead of making a sub-collection inside user document and incurring these problems, just keep all fields in the top level document(user document), allowing users to update any field.
match /users/userId
allow update, read: if true;
allow create, remove: if false;But make an (onUpdate) cloud function to listen on user document update and
detect changes in fields which aren't allowed to be modified by the user, so
if the user tried to change these fields I can detect this and return modified fields to their previous values like this:export const updateUser = functions.firestore
.document('users/userId')
.onUpdate((change, context) =>
const previousValue = change.before.data().securedField;
const newValue = change.after.data().securedField;
if (previousValue !== newValue)
return db.collection('users')
.doc(context.params.userId)
.update( securedField: previousValue );
);
Is the second solution secure? which is the best solution for this? or any other solutions?
firebase google-cloud-firestore google-cloud-functions firebase-security-rules
firebase google-cloud-firestore google-cloud-functions firebase-security-rules
edited Dec 6 '18 at 22:53
Rabia Hamouda
asked Nov 14 '18 at 13:55
Rabia HamoudaRabia Hamouda
133
133
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
Your approach is definitely a possibility, and an interesting use of Cloud Functions. But there will be a delay between the write operation from the user, and the moment the Cloud Function detects and reverts the change.
I'd probably catch the situation in security rules. While you can't deny the user from writing the field in security rules, you can ensure that they can only write the same value to a field that currently has. That effectively also makes it impossible for them to change the value of a field. You do this by:
allow write: if request.resource.data.securedField == resource.data.securedField;
This rule ensures that the field in the updated document (request.resource.data.securedField) has the same value as that field in the current document(resource.data.securedField).
Thank you very much! this worked for me, you really helped me a lot, actually I have read this in the firebase docs before, but it didn't occur to me that it would be used here.
– Rabia Hamouda
Nov 14 '18 at 15:55
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53301895%2fan-issue-with-preventing-users-from-changing-specific-document-fields-in-firesto%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Your approach is definitely a possibility, and an interesting use of Cloud Functions. But there will be a delay between the write operation from the user, and the moment the Cloud Function detects and reverts the change.
I'd probably catch the situation in security rules. While you can't deny the user from writing the field in security rules, you can ensure that they can only write the same value to a field that currently has. That effectively also makes it impossible for them to change the value of a field. You do this by:
allow write: if request.resource.data.securedField == resource.data.securedField;
This rule ensures that the field in the updated document (request.resource.data.securedField) has the same value as that field in the current document(resource.data.securedField).
Thank you very much! this worked for me, you really helped me a lot, actually I have read this in the firebase docs before, but it didn't occur to me that it would be used here.
– Rabia Hamouda
Nov 14 '18 at 15:55
add a comment |
Your approach is definitely a possibility, and an interesting use of Cloud Functions. But there will be a delay between the write operation from the user, and the moment the Cloud Function detects and reverts the change.
I'd probably catch the situation in security rules. While you can't deny the user from writing the field in security rules, you can ensure that they can only write the same value to a field that currently has. That effectively also makes it impossible for them to change the value of a field. You do this by:
allow write: if request.resource.data.securedField == resource.data.securedField;
This rule ensures that the field in the updated document (request.resource.data.securedField) has the same value as that field in the current document(resource.data.securedField).
Thank you very much! this worked for me, you really helped me a lot, actually I have read this in the firebase docs before, but it didn't occur to me that it would be used here.
– Rabia Hamouda
Nov 14 '18 at 15:55
add a comment |
Your approach is definitely a possibility, and an interesting use of Cloud Functions. But there will be a delay between the write operation from the user, and the moment the Cloud Function detects and reverts the change.
I'd probably catch the situation in security rules. While you can't deny the user from writing the field in security rules, you can ensure that they can only write the same value to a field that currently has. That effectively also makes it impossible for them to change the value of a field. You do this by:
allow write: if request.resource.data.securedField == resource.data.securedField;
This rule ensures that the field in the updated document (request.resource.data.securedField) has the same value as that field in the current document(resource.data.securedField).
Your approach is definitely a possibility, and an interesting use of Cloud Functions. But there will be a delay between the write operation from the user, and the moment the Cloud Function detects and reverts the change.
I'd probably catch the situation in security rules. While you can't deny the user from writing the field in security rules, you can ensure that they can only write the same value to a field that currently has. That effectively also makes it impossible for them to change the value of a field. You do this by:
allow write: if request.resource.data.securedField == resource.data.securedField;
This rule ensures that the field in the updated document (request.resource.data.securedField) has the same value as that field in the current document(resource.data.securedField).
answered Nov 14 '18 at 14:11
Frank van PuffelenFrank van Puffelen
234k29380407
234k29380407
Thank you very much! this worked for me, you really helped me a lot, actually I have read this in the firebase docs before, but it didn't occur to me that it would be used here.
– Rabia Hamouda
Nov 14 '18 at 15:55
add a comment |
Thank you very much! this worked for me, you really helped me a lot, actually I have read this in the firebase docs before, but it didn't occur to me that it would be used here.
– Rabia Hamouda
Nov 14 '18 at 15:55
Thank you very much! this worked for me, you really helped me a lot, actually I have read this in the firebase docs before, but it didn't occur to me that it would be used here.
– Rabia Hamouda
Nov 14 '18 at 15:55
Thank you very much! this worked for me, you really helped me a lot, actually I have read this in the firebase docs before, but it didn't occur to me that it would be used here.
– Rabia Hamouda
Nov 14 '18 at 15:55
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53301895%2fan-issue-with-preventing-users-from-changing-specific-document-fields-in-firesto%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown