Firestore规则:验证数据没有字段

时间:2018-09-10 16:45:33

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

所以我目前对所有用户都有两个角色:isAdmin和isReader。

允许Admin读写数据,而允许Reader读取数据。

当某人创建帐户时,他没有权利。甚至没有isReader。只有管​​理员可以更改规则。

这是我打算这样做的方式:

一旦有人创建了帐户,我将在Users集合中创建一个文档,如下所示:

uid: user.uid,
email: user.email,
role: {
    isAdmin: false,
    isReader: false,
}

每次登录时,我都会更新“电子邮件”和uid,但保持role不变。为了确保这种行为,我有以下规则:

match /Users/{userId} {
  allow read: if isOwner(userId) || isAdmin();
  allow create: if request.resource.data.hasAll(['uid', 'email', 'role']) && request.resource.data.role.isAdmin == false && request.resource.data.role.isReader == false;
  allow update: if resource.data.role == null || isAdmin();
}

function isAdmin() {
  return getUserData().role.isAdmin == true;
}

我认为我有2个错误:

  1. 由于某些原因,data.hasAll(['uid', 'email', 'role'])无法正常工作。当我删除此部分时,create规则按计划进行。

  2. resource.data.role == null不起作用。我打算检查数据是否包含role的任何更新,因为我不允许,因为它不是来自管理员。但是由于某种原因,它不起作用。

有人知道我在做什么错吗?另外,我的策略是否还可以保存?还是有人可以“破解”自己的读者或管理员权限?

2 个答案:

答案 0 :(得分:2)

这看起来可能是自定义auth声明的好用例。您可以在安全环境中为用户设置特定角色,如this codelab所示。以下是在服务器中设置自定义声明的示例。您甚至可以为此使用Cloud Functions。我建议您检查一下Codelab的完整代码,以便了解如何确保不仅有人可以请求向其用户添加自定义声明。

admin.auth().setCustomUserClaims(uid, {Admin: true}).then(() => {
// The new custom claims will propagate to the user's ID token the
// next time a new one is issued.
});

然后,您可以在安全规则中检查用户的那些角色。

service cloud.firestore {
  match /databases/{database}/documents {
    match /Users/{userId} {
      allow read: if request.auth.token.Owner == true || request.auth.token.Admin == true;
      allow create: request.auth.uid == userId && 
      request.resource.data.uid == request.auth.uid &&
      request.resource.data.email != null;
      allow update: request.auth.uid == userId || request.auth.token.Admin == true;
    }
  }
}

请注意,由于不再需要有关“角色”的所有规则,因此已将其删除。如果您对实施有任何疑问,请告诉我,因为这是一个普遍的问题,因此我想在此方面做更多的介绍。

答案 1 :(得分:1)

request.resource.data.hasAll(['uid', 'email', 'role'])不起作用,因为request.resource.dataMap而不是List。您应该使用keys()List创建一个Map,并确保存在某些密钥。

关于第二个问题,您应该只检查是否有对rolesallow update: if !('roles' in request.writeFields) || isAdmin();的写操作。除非用户是管理员,否则这将确保对roles的所有更新都将失败。

关于您的安全性问题;我看到几个问题。首先是任何人都可以创建无限的用户,这也意味着任何管理员都可以创建无限的其他管理员帐户。为了阻止这种情况的发生,我将在allow create中添加另一个部分,以限制用户的创建:

allow create: if userId == request.resource.data.uid
  && request.auth.uid == request.resource.data.uid
  && request.resource.data.hasAll(['uid', 'email', 'role'])
  && request.resource.data.role.isAdmin == false
  && request.resource.data.role.isReader == false;`

第二个是任何人都可以更改其uid并尝试假冒其他人。显然,这不会改变与他们的Auth令牌相关联的uid,但是取决于您如何编写其余规则,后端安全性甚至前端显示,有人可以利用该缺陷来利用您的代码或另一个用户(可能是管理员)。您可以通过检查uid中是否存在writeFields来确保没有人更改(您还需要以前的安全解决方案来确保他们在创建过程中不会冒充 )。

allow update: if !('uid' in request.writeFields)
  && (!('roles' in request.writeFields) || isAdmin());

我希望这会有所帮助。