Firebase数据库快速入门处理的方式是否安全?
我想为文章喜欢创build一个增量字段。
我指的是这个链接: 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<>();
并且会毁掉其他已经喜欢它的用户的逻辑。
我甚至不认为你可以为此制定规则,特别是对于“减less计数”行为。
任何帮助,build议?
安全规则可以做一些事情:
-
确保用户只能添加/删除自己的
stars
节点的uid
"stars": { "$uid": { ".write": "$uid == auth.uid" } }
-
确保用户只有在将自己的
uid
添加到stars
节点或将其从中删除时才能更改starCount
- 确保用户只能增加/减less
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
- 确保用户只能添加/删除自己的投票
- 确保增加票数的同时进行表决
- 确保计数减less是伴随着“unvote”
- 确保投票同时增加
请注意,规则不会:
- 确保“unvote”伴随计数减less(可以使用
.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" }
用一些代码来testing这个jsbin: http ://jsbin.com/yaxexe/edit?js,console