Firebase 数据库快速入门处理计数的方式是否安全? [英] Is the way the Firebase database quickstart handles counts secure?

查看:26
本文介绍了Firebase 数据库快速入门处理计数的方式是否安全?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to create an increment field for article likes.

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

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

In the example there is code for increment field:

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);
}

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

But how can I be sure if the user already liked/unliked the article?

在这个例子中,用户(黑客)也可以像这样清除整个星星地图,它无论如何都会保存:

In the example, user (hacker) might as well clear whole stars Map like this and it will save anyway:

p.stars = new HashMap<>();

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

and it will ruin the logic for other users who were already liked it.

我什至不认为您可以为此制定规则,尤其是减少计数"操作.

I do not even think you can make rules for this, especially for "decrease count" action.

有什么帮助、建议吗?

推荐答案

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

The security rules can do a few things:

  • 确保用户只能向stars节点添加/删除他们自己的uid

  • ensure that a user can only add/remove their own uid to the stars node

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

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

  • ensure that a user can only change the starCount when they are adding their own uid to the stars node or removing it from there

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

    Even with these, it might indeed still be tricky to have a security rule that ensures that the starCount is equal to the number of uids in the stars node. I encourage you to try it though, and share your result.

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

    The way I've seen most developers deal with this though is:

    • 在客户端开始计数(如果stars节点的大小不是太大,这是合理的).
    • 在服务器上运行一个受信任的进程,该进程将 stars 聚合到 starCount 中.它可以使用 child_ added/child_removed 事件进行递增/递减.
    • do the start counting on the client (if the size of the stars node is not too large, this is reasonable).
    • have a trusted process running on a server that aggregates the stars into starCount. It could use child_added/child_removed events for incrementing/decrementing.

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

    I wrote up a working example of a voting system. The data structure is:

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

    当用户投票时,应用会发送多位置更新:

    When a user votes, the app sends a multi-location update:

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

    然后取消他们的投票:

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

    这意味着应用程序需要显式读取 voteCount 的当前值,使用:

    This means the app needs to explicitly read the current value for voteCount, with:

    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 和服务器本身.

    It's essentially a multi-location transaction, but then built in app code and security rules instead of the Firebase SDK and server itself.

    安全规则做了几件事:

    1. 确保voteCount只能增加或减少1
    2. 确保用户只能添加/删除自己的投票
    3. 确保计数增加伴随着投票
    4. 确保计数减少伴随着取消投票"
    5. 确保投票伴随计数增加

    注意规则不:

    • 确保取消投票"伴随着计数减少(可以使用 .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,控制台

    jsbin with some code to test this: http://jsbin.com/yaxexe/edit?js,console

    这篇关于Firebase 数据库快速入门处理计数的方式是否安全?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆