Firebase 数据库快速入门处理计数的方式是否安全? [英] Is the way the Firebase database quickstart handles counts secure?
问题描述
我想为文章喜欢创建一个增量字段.
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 thestars
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
intostarCount
. 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.
安全规则做了几件事:
- 确保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,控制台
jsbin with some code to test this: http://jsbin.com/yaxexe/edit?js,console
这篇关于Firebase 数据库快速入门处理计数的方式是否安全?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!