【问题标题】:How do I secure fields on a Firestore document when allowing update?允许更新时如何保护 Firestore 文档中的字段?
【发布时间】:2019-09-10 03:35:12
【问题描述】:

使用 Firebase Firestore,我将聊天室详细信息存储在包含以下数据的文档中:

roomName
roomAvatar
createDate
isDeleted

我的应用程序和我的规则要求在“创建”文档时设置这些字段。但是,我也希望授权用户也可以“更新”文档。

我已经进行了检查,只允许某些用户更新文档并验证他们不允许修改像“createDate”这样的字段。但是,我似乎无法创建一个规则来强制授权用户不删除“createDate”字段,无论是通过传递 FiledValue.delete() 还是使用 ref.set(objectMissingCreateDate)。

最后,如果客户端只尝试更新一个或两个字段,我认为不应该要求客户端在更新时传递所有数据字段。

我有一个“更新”规则如下:

allow update: if isAuthenticated() && isMemberOfRoom() && 
  (
    (!("roomName" in request.resource.data) || 
      request.resource.data.roomName == resource.data.roomName || 
      hasRoomPermission("UpdateRoom")) &&
    (!("roomAvatar" in request.resource.data) || 
      request.resource.data.roomAvatar == resource.data.roomAvatar || 
      hasRoomPermission("UpdateRoom")) &&
    (!("createDate" in request.resource.data) || 
      request.resource.data.createDate == resource.data.createDate) &&
    (!("isDeleted" in request.resource.data) || 
      request.resource.data.isDeleted == resource.data.isDeleted || 
      hasRoomPermission("DeleteRoom"))
  );

主要问题是保护数据不被授权用户传入 FieldValue.delete() 或使用 [Android] docRef.set() 而缺少必需的值。

我什至会接受为非管理员客户端关闭 FieldValue.delete() 和破坏性“设置”操作的功能。

【问题讨论】:

  • 通过我对 Firestore 规则模拟器的实验,简单地说 allow write: if "foo" in request.resource.data; 允许在以前存在时未指定 foo 的部分更新,并防御 {foo: FieldValue.delete()}。
  • “我认为如果客户端只尝试更新一个或两个字段,我认为不应该要求客户端在更新时传递所有数据字段。”他们不必那样做。 request.resource 包含允许更新时的值。因此,如果文档包含 3 个字段,其中一个已更新,request.resource 包含这 3 个字段,如果允许更新,它们将是。
  • 感谢您对规则流中数据评估方式的说明。我已经为我的问题添加了一个似乎有效的答案。我非常感谢 Firebase 团队的快速响应!

标签: firebase google-cloud-firestore firebase-security


【解决方案1】:

在 Doug 和 Puff 的 cmets 的帮助下,我意识到自己做错了什么。

首先,我不知道仅传递几个字段的更新(或带有合并选项的集合)会导致其余字段从数据库的 resource 复制到 request.resource。

其次,设置(不合并)或传入FieldValue.delete() 将是request.resource 缺少现有文档字段的唯一方法。

有了这些新知识,我将之前的规则更新为以下内容:

allow update: if isAuthenticated() && isMemberOfRoom() && 
  (
    ("roomName" in request.resource.data && 
      (request.resource.data.roomName == resource.data.roomName || 
      hasRoomPermission("UpdateRoom"))) &&
    ("roomAvatar" in request.resource.data && 
      (request.resource.data.roomAvatar == resource.data.roomAvatar || 
      hasRoomPermission("UpdateRoom"))) &&
    ("createDate" in request.resource.data && 
      request.resource.data.createDate == resource.data.createDate) &&
    ("isDeleted" in request.resource.data && 
      (request.resource.data.isDeleted == resource.data.isDeleted || 
      hasRoomPermission("DeleteRoom")))
  );

这些新规则现在为客户锁定createDate,同时允许通过权限测试的客户编辑roomName、roomAvatar 和isDeleted。它也不允许使用FieldValue.delete() 或调用docRef.set(object) 更新这些字段中的任何一个,其中对象缺少这些字段之一。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-06-19
    • 2018-09-15
    • 1970-01-01
    • 1970-01-01
    • 2020-05-31
    • 1970-01-01
    • 1970-01-01
    • 2021-12-04
    相关资源
    最近更新 更多