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 身份验证和数据库实时之间事务的最佳方式