Firebase 数据库快速入门处理计数的方式是不是安全?

Posted

技术标签:

【中文标题】Firebase 数据库快速入门处理计数的方式是不是安全?【英文标题】:Is the way the Firebase database quickstart handles counts secure?Firebase 数据库快速入门处理计数的方式是否安全? 【发布时间】:2016-10-23 13:55:15 【问题描述】:

我想为文章喜欢创建一个增量字段。

我指的是这个链接:https://firebase.google.com/docs/database/android/save-data#save_data_as_transactions

在示例中有增量字段的代码:

if (p.stars.containsKey(getUid())) 
    // Unstar the post and remove self from stars
    p.starCount = p.starCount - 1;
    p.stars.remove(getUid());
 else 
    // Star the post and add self to stars
    p.starCount = p.starCount + 1;
    p.stars.put(getUid(), true);

但是我如何确定用户是否已经喜欢/不喜欢这篇文章?

在示例中,用户(黑客)不妨像这样清除整个星图,并且无论如何它都会保存:

p.stars = new HashMap<>();

它会破坏其他已经喜欢它的用户的逻辑。

我什至认为您无法为此制定规则,尤其是对于“减少计数”操作。

有什么帮助、建议吗?

【问题讨论】:

你是如何在你的数据库中保存这些信息的? 【参考方案1】:

安全规则可以做一些事情:

确保用户只能将自己的uid 添加/删除到stars 节点

"stars": 
  "$uid": 
    ".write": "$uid == auth.uid"
  

确保用户只有在将自己的uid 添加到stars 节点或从那里删除它时才能更改starCount

确保用户只能将starCount 增加/减少1

即使有这些,要确保starCount 等于stars 节点中的uid 数量的安全规则确实可能仍然很棘手。不过,我鼓励您尝试一下,并分享您的结果。

不过,我看到大多数开发人员处理这个问题的方式是:

在客户端做开始计数(如果stars节点的大小不是太大,这是合理的)。 在将stars 聚合到starCount 的服务器上运行一个受信任的进程。它可以使用 child_added/child_removed 事件进行递增/递减。

更新:带有工作示例

我写了一个投票系统的工作示例。数据结构为:

votes: 
  uid1: true,
  uid2: true,
,
voteCount: 2

当用户投票时,应用会发送多地点更新:


  "/votes/uid3": true,
  "voteCount": 3

然后取消他们的投票:


  "/votes/uid3": null,
  "voteCount": 2

这意味着应用需要显式读取voteCount 的当前值,其中:

function vote(auth) 
  ref.child('voteCount').once('value', function(voteCount) 
    var updates = ;
    updates['votes/'+auth.uid] = true;
    updates.voteCount = voteCount.val() + 1;
    ref.update(updates);
  );  

它本质上是一个多地点事务,但随后内置了应用代码和安全规则,而不是 Firebase SDK 和服务器本身。

安全规则做了几件事:

    确保 voteCount 只能上升或下降 1 确保用户只能添加/删除自己的投票 确保计数增加伴随着投票 确保计数减少伴随着“取消投票” 确保投票伴随计数增加

请注意,规则不会:

确保“取消投票”伴随着计数减少(可以使用.write 规则完成) 重试失败的投票/取消投票(处理并发投票/取消投票)

规则:

"votes": 
    "$uid": 
      ".write": "auth.uid == $uid",
      ".validate": "(!data.exists() && newData.val() == true &&
                      newData.parent().parent().child('voteCount').val() == data.parent().parent().child('voteCount').val() + 1
                    )"
    
,
"voteCount": 
    ".validate": "(newData.val() == data.val() + 1 && 
                   newData.parent().child('votes').child(auth.uid).val() == true && 
                   !data.parent().child('votes').child(auth.uid).exists()
                  ) || 
                  (newData.val() == data.val() - 1 && 
                   !newData.parent().child('votes').child(auth.uid).exists() && 
                   data.parent().child('votes').child(auth.uid).val() == true
                  )",
    ".write": "auth != null"

jsbin 用一些代码来测试这个:http://jsbin.com/yaxexe/edit?js,console

【讨论】:

感谢您的想法,看起来他们中的大多数都适用于我的情况。 该死...我希望你能通过规则来保护它。 :-) 我真的很想在某个时候看到一个人能做到多近。 Firebase 规则非常有限。尤其是当所有上层“写”规则覆盖任何下层规则时。你的规则有一个问题,如果我想让这个较低的“$uid == auth.uid”工作,我不能为上面的“$article_id”列添加写权限。所以基本上没有人有权在上面的“文章”中创建一个新条目。我对 firebase 大肆宣传,但这些规则非常有限,你甚至无法用它们解决简单的问题。 FIrebase 的安全规则“有些不合常规”。但是,如果您花时间仔细研究它们,这些规则会非常强大。我们已经看到人们在其中实现了游戏事务(类似于两阶段提交的交互),以及许多更常见的安全和验证系统。 那么请详细说明您建议如何让".write": "$uid == auth.uid" 在“星级”级别上工作。因为我在父级别收到此错误:/article-favorites/-KK9xFyA8skOvSLhaHWq 处的事务失败:DatabaseError: Permission denied 但是如果我将写入规则添加到“文章收藏夹”,那么更深的 uid 检查将被忽略。我错过了什么吗?我可以为此目的使用“.validate”吗?

以上是关于Firebase 数据库快速入门处理计数的方式是不是安全?的主要内容,如果未能解决你的问题,请参考以下文章

处理 Firebase 身份验证和数据库实时之间事务的最佳方式

Firebase 实时数组计数不匹配

Firebase - 始终检查用户是不是登录的最佳方式?

如何通过 Firebase 云消息发送推送通知(快速入门)?

firebase 快速入门 ios 示例

处理由于 Firebase 查询中的高元素计数而导致的内存使用情况