Firebase数据库快速入门处理的方式是否安全? [英] Is the way the Firebase database quickstart handles counts secure?
问题描述
我指的是这个链接: https://firebase.google.com/docs/database/android/save-data#save_data_as_transactions
$ b $ (p.stars.containsKey(getUid())在这个例子中,有一个增量字段的代码:
if ){
//取消星标,从星星中删除自己
p.starCount = p.starCount - 1;
p.stars.remove(getUid());
} else {
//为帖子加星标并将自己添加到stars
p.starCount = p.starCount + 1;
p.stars.put(getUid(),true);
}
但是我怎么能确定用户是否已经喜欢/不喜欢这篇文章?在这个例子中,用户(黑客)可能会像这样清除整个星星图,它将会保存:
p.stars = new HashMap<>();
并且会毁掉其他已经喜欢的用户的逻辑。
我甚至不认为你可以为此制定规则,特别是对于减少计数操作。
任何帮助,建议? / p>
安全规则可以做一些事情: 确保用户只能将自己的
uid
添加到 stars
节点
stars:{
$ uid:{
.write:$ uid == auth.uid
}
确保用户只能在将 uid
添加到星号时才能更改
节点或从那里删除 starCount
starCount
by 1 即使有了这些,确实有一个安全规则可能确实很棘手, starCount
等于 stars
节点中的uid数量。我鼓励你尝试一下,并分享你的结果。
我发现大多数开发者处理这个问题的方式是:
- 开始计算客户端(如果
stars >节点的大小不是太大,这是合理的)。
集合到
- 在服务器上运行的可信进程将
stars starCount
。它可以使用child_added / child_removed事件递增/递减。
$ b $ h2更新:与工作示例
我写了一个投票系统的实例。数据结构是:
pre code> 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);
});
$ b它本质上是一个多位置事务,但是内置了应用程序代码和安全规则,而不是Firebase SDK和服务器本身。
安全规则会执行一些操作:
- 确保voteCount只能上升或下降1 /
- 确保用户只能添加/删除他们自己的投票
- 确保unvote伴有计数减少(可以使用
.write
规则)
- 重试失败的投票/ unvotes(处理并发投票/ unvoting)
$ b $ 规则:
votes:{
$ uid:{
.write:auth.uid = = $ uid,
.validate:(!data.exists()&& newData.val()== true&& $()$ b $ newData.parent()。parent()。child('voteCount')。val()== data.parent()。parent()。child('voteCount')。val()+ 1
$ b $ vote_quot:{
.validate:(newData.val()== data.val()+ 1& amp; ;&
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用一些代码来测试这个: a href =http://jsbin.com/yaxexe/edit?js,console =noreferrer> http://jsbin.com/yaxexe/edit?js,console
I want to create an increment field for article likes.
I am referring to this link: https://firebase.google.com/docs/database/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.
Any help, suggestions?
解决方案The security rules can do a few things:
ensure that a user can only add/remove their own
uid
to thestars
node"stars": { "$uid": { ".write": "$uid == auth.uid" } }
ensure that a user can only change the
starCount
when they are adding their ownuid
to thestars
node or removing it from there- ensure that the user can only increase/decrease
starCount
by 1
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 thestars
node. I encourage you to try it though, and share your result.The way I've seen most developers deal with this though is:
- 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.
Update: with working example
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 }
And then to remove their vote:
{ "/votes/uid3": null, "voteCount": 2 }
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); }); }
It's essentially a multi-location transaction, but then built in app code and security rules instead of the Firebase SDK and server itself.
The security rules do a few things:
- ensure that the voteCount can only go up or down by 1
- ensure that a user can only add/remove their own vote
- ensure that a count increase is accompanied by a vote
- ensure that a count decrease is accompanied by a "unvote"
- ensure that a vote is accompanied by a count increase
Note that the rules don't:
- ensure that an "unvote" is accompanied by a count decrease (can be done with a
.write
rule) - retry failed votes/unvotes (to handle concurrent voting/unvoting)
The rules:
"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 with some code to test this: http://jsbin.com/yaxexe/edit?js,console
这篇关于Firebase数据库快速入门处理的方式是否安全?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- 重试失败的投票/ unvotes(处理并发投票/ unvoting)
请注意,规则不会:
- 在服务器上运行的可信进程将