Firestore 规则:resource.data.keys() 不包含读取中的所有字段

ame*_*n73 7 security firebase firebase-security google-cloud-firestore

设置


我在 Firebase Firestore 中有一个集合,其中包含以下字段:

(["active" , "created" , "description" , "displayName" , "expires" , "image" , "type" , "uid" , "userName"])
Run Code Online (Sandbox Code Playgroud)

其中"expires"是可选的。

写入规则确保每个对象都遵循该形式并成功测试。

问题


当尝试从集合中读取时,我有一条规则,规定如下:

let seeUnexpired = !("expires" in resource.data.keys()) ||
resource.data.expires > request.time ||
request.auth.uid == resource.data.uid;
Run Code Online (Sandbox Code Playgroud)

这禁止除作者之外的用户阅读过期的条目。然而,这条规则并不禁止读取。我正在使用带有精心策划的数据的本地模拟器进行测试,并且确信过期字段存在并且对于此测试来说已经过时。

细节


在尝试调试时,我发现导致规则失败的条件是!("expires" in resource.data.keys())

运行测试并debug(resource.data.keys())打印此对象firestore-debug.log

list_value {
  values {
    string_value: "active"
  }
}
Run Code Online (Sandbox Code Playgroud)

where"active"仅在请求中使用此查询条件时显示:...collection('collection_name').where('active', '==', true).get()

这对我来说仅包括读取请求的子句resource.data.keys()中引用的资源中的字段。where这意味着请求可以通过简单地将其不包含在查询中来规避“字段不得存在”规则。

调试:

Mar 31, 2021 12:34:48 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
INFO: Detected non-HTTP/2 connection.
list_value {
  values {
    string_value: "active"
  }
}
Run Code Online (Sandbox Code Playgroud)

测试


测试:

Mar 31, 2021 12:34:48 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
INFO: Detected non-HTTP/2 connection.
list_value {
  values {
    string_value: "active"
  }
}
Run Code Online (Sandbox Code Playgroud)

规则:

await firestoreAdmin.collection(COLLECTIONS.items).doc(mockItem.id).update({active: true, expires: new Date('01 Jan 2000 00:00:00 GMT')});
const query = firestore.collection(COLLECTIONS.items).where('active', '==', true); //unAuthed firestore instance
await assertFails(query.get());
Run Code Online (Sandbox Code Playgroud)

数据: Firestore 模拟器数据

问题


我对这个问题的理解是否准确,或者我是否遗漏了细节或语法怪癖?这种行为是故意的吗?如果是的话,我应该如何修改我的规则/数据以强制执行这种安全性?

ame*_*n73 3

我的发现是,对于读取规则,firestore 似乎只加载查询中提到的文档中的字段。这对于要求字段存在或匹配某些内容的规则很有意义,因为如果您不将其包含在查询中,它们肯定会失败(因为它们将针对未定义的内容进行测试)。它在这里不起作用,因为如果您从查询中省略它,无论如何它都会通过不存在规则,因为 firestore 在执行检查时从整个资源中省略了该字段。

我的解决方案只是添加另一个布尔字段“hasExpiration”,指示“expires”字段是否存在。我对这个解决方案有点不满意,因为它增加了复杂性并落在客户端/写入规则上以确保这些字段之间存在奇偶校验。

https://firebase.google.com/docs/firestore/security/rules-query#rules_are_not_filters

https://firebase.google.com/docs/firestore/security/rules-struct#capsular_operations

  • 我发现这绝对令人难以置信,这没有得到很好的记录。这是危险的意外行为,与 Firebase 文档直接矛盾。Firebase 文档说“资源变量引用请求的文档,resource.data 是存储在文档中的所有字段和值的映射。有关资源变量的更多信息,请参阅参考文档。” 链接的文档说资源是“正在读取或写入的 firestore 文档”。data 是“文档数据的地图”。没有提到这个案例,这不是真的! (3认同)