首页 > 解决方案 > 允许更新时如何保护 Firestore 文档中的字段?

问题描述

使用 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() 和破坏性“设置”操作的功能。

标签: firebasegoogle-cloud-firestorefirebase-security

解决方案


在 Doug 和 Puff 的评论的帮助下,我意识到我做错了什么。

首先,我不知道只传递几个字段的更新(或带有合并选项的集合)会导致其余字段request.resource从数据库的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为客户端锁定,同时允许编辑roomNameroomAvatarisDeleted通过权限测试的客户端。它也不允许在对象缺少这些字段之一的地方更新FieldValue.delete()或调用这些字段中的任何一个。docRef.set(object)


推荐阅读