使投票系统安全 Meteor.Methods
Making Vote System Secure Meteor.Methods
我正在尝试实施一个安全的投票系统,并且无法通过客户端控制台的 Meteor.call() 进行更改。每个人都可以在登录后对 post 进行上下投票。但每个用户和 post 一次只能投票一次。
只有我的客户端我得到了这样的东西:
Template.postArgument.events({
'click .yes':function() {
if(Meteor.user()) {
var postId = Arguments.findOne({_id:this._id})
var currentArgumentId = this._id;
if($.inArray(Meteor.userId(), postId.votedUp) ===-1) {
if($.inArray(Meteor.userId(), postId.votedDown) !==-1) {
Meteor.call('argumentVoteYes',currentArgumentId);
} else {
Meteor.call('argumentVoteYesElse',currentArgumentId);
}
} else {
Meteor.call('argumentVoteYesElseElse',currentArgumentId);
}
}
}}
)};
在我的服务器上:
Meteor.methods({
'argumentVoteYes':function(currentArgumentId){
Arguments.update(currentArgumentId, {
$pull: {votedDown: Meteor.userId()},
$inc: {score: 2 },
$addToSet: {votedUp: Meteor.userId() }
});
},
'argumentVoteYesElse':function(currentArgumentId){
Arguments.update(currentArgumentId, {
$inc: {score: 1 },
$addToSet: {votedUp: Meteor.userId() }
});
},
'argumentVoteYesElseElse':function(currentArgumentId){
Arguments.update(currentArgumentId, {
$inc: {score: -1 },
$pull: {votedUp: Meteor.userId()}
});
}
'argumentVoteNo':function(currentArgumentId){
Arguments.update(currentArgumentId, {
$pull: {votedUp: Meteor.userId()},
$inc: {score: -2 },
$addToSet: {votedDown: Meteor.userId() },
});
},
'argumentVoteNoElse':function(currentArgumentId){
Arguments.update(currentArgumentId, {
$inc: {score: -1 },
$addToSet: {votedDown: Meteor.userId() },
});
},
'argumentVoteNoElseElse':function(currentArgumentId){
Arguments.update(currentArgumentId, {
$inc: {score: 1 },
$pull: {votedDown: Meteor.userId()}
});
},
});
问题是我如何确保这个安全,例如,如果有人调用 Meteor.call('argumentvoteYes', "someID" , {$inc: {score:2}});
它将增加 2 的分数。如果用户调用它两次,投票将增加 4。有什么办法吗这样做安全吗?
您需要检查用户是否在服务器上的 votedUp/down 数组中。您在客户端拥有正确的逻辑,因此只需在服务器上进行实际更新之前应用相同的逻辑即可。
您不必担心方法中会出现额外的增量,因为您的方法只接受一个参数。但是,您确实需要防范其他黑客攻击:
让我们首先扩展 Match
对象,以便我们可以检查 _id
是否就是:
Match._id = Match.Where(function(id){
check(id, String); // first make sure we're dealing with a string
// then grep for an exactly 17 character alphanumeric string
return /^[a-zA-Z0-9]{17,17}/.test(id);
});
现在让我们来看看你的第一个方法:
Meteor.methods({
'argumentVoteYes':function(currentArgumentId){
check(currentArgumentId,Match._id); // will error if not an _id
var post = Arguments.findOne({ _id: currentArgumentId });
var userId = Meteor.userId(); // the current user
if ( post && userId ){ // make sure a real user is operating on an actual document
// only update if no votes have been recorded OR
// user hasn't already voted
if ( !post.votedUp || post.votedUp.indexOf(userId) === -1 ){
Arguments.update(currentArgumentId, {
$pull: { votedDown: userId },
$inc: { score: 2 },
$addToSet: {votedUp: userId }
});
}
}
},
我之前也有同样的想法,我找到了解决方案,只使用一个你不从客户端传递的 userId 数组(你只保存当前用户的 ID)并计算数组中的总 ID。它不会添加相同的 ID 两次。
从我的代码(你可以做剩下的检查,比如用户是否在不喜欢的数组中,做一些事情等):
likeActivity: function (activityId) {
Activities.update(activityId,{
$addToSet: {
likers: this.userId,
}
});
},
unlikeActivity: function (activityId) {
Activities.update(activityId,{
$pull: {
likers: this.userId,
}
})
}
在我的助手中:
likeCount: function() {
return this.likers.length
}
我正在尝试实施一个安全的投票系统,并且无法通过客户端控制台的 Meteor.call() 进行更改。每个人都可以在登录后对 post 进行上下投票。但每个用户和 post 一次只能投票一次。
只有我的客户端我得到了这样的东西:
Template.postArgument.events({
'click .yes':function() {
if(Meteor.user()) {
var postId = Arguments.findOne({_id:this._id})
var currentArgumentId = this._id;
if($.inArray(Meteor.userId(), postId.votedUp) ===-1) {
if($.inArray(Meteor.userId(), postId.votedDown) !==-1) {
Meteor.call('argumentVoteYes',currentArgumentId);
} else {
Meteor.call('argumentVoteYesElse',currentArgumentId);
}
} else {
Meteor.call('argumentVoteYesElseElse',currentArgumentId);
}
}
}}
)};
在我的服务器上:
Meteor.methods({
'argumentVoteYes':function(currentArgumentId){
Arguments.update(currentArgumentId, {
$pull: {votedDown: Meteor.userId()},
$inc: {score: 2 },
$addToSet: {votedUp: Meteor.userId() }
});
},
'argumentVoteYesElse':function(currentArgumentId){
Arguments.update(currentArgumentId, {
$inc: {score: 1 },
$addToSet: {votedUp: Meteor.userId() }
});
},
'argumentVoteYesElseElse':function(currentArgumentId){
Arguments.update(currentArgumentId, {
$inc: {score: -1 },
$pull: {votedUp: Meteor.userId()}
});
}
'argumentVoteNo':function(currentArgumentId){
Arguments.update(currentArgumentId, {
$pull: {votedUp: Meteor.userId()},
$inc: {score: -2 },
$addToSet: {votedDown: Meteor.userId() },
});
},
'argumentVoteNoElse':function(currentArgumentId){
Arguments.update(currentArgumentId, {
$inc: {score: -1 },
$addToSet: {votedDown: Meteor.userId() },
});
},
'argumentVoteNoElseElse':function(currentArgumentId){
Arguments.update(currentArgumentId, {
$inc: {score: 1 },
$pull: {votedDown: Meteor.userId()}
});
},
});
问题是我如何确保这个安全,例如,如果有人调用 Meteor.call('argumentvoteYes', "someID" , {$inc: {score:2}});
它将增加 2 的分数。如果用户调用它两次,投票将增加 4。有什么办法吗这样做安全吗?
您需要检查用户是否在服务器上的 votedUp/down 数组中。您在客户端拥有正确的逻辑,因此只需在服务器上进行实际更新之前应用相同的逻辑即可。
您不必担心方法中会出现额外的增量,因为您的方法只接受一个参数。但是,您确实需要防范其他黑客攻击:
让我们首先扩展 Match
对象,以便我们可以检查 _id
是否就是:
Match._id = Match.Where(function(id){
check(id, String); // first make sure we're dealing with a string
// then grep for an exactly 17 character alphanumeric string
return /^[a-zA-Z0-9]{17,17}/.test(id);
});
现在让我们来看看你的第一个方法:
Meteor.methods({
'argumentVoteYes':function(currentArgumentId){
check(currentArgumentId,Match._id); // will error if not an _id
var post = Arguments.findOne({ _id: currentArgumentId });
var userId = Meteor.userId(); // the current user
if ( post && userId ){ // make sure a real user is operating on an actual document
// only update if no votes have been recorded OR
// user hasn't already voted
if ( !post.votedUp || post.votedUp.indexOf(userId) === -1 ){
Arguments.update(currentArgumentId, {
$pull: { votedDown: userId },
$inc: { score: 2 },
$addToSet: {votedUp: userId }
});
}
}
},
我之前也有同样的想法,我找到了解决方案,只使用一个你不从客户端传递的 userId 数组(你只保存当前用户的 ID)并计算数组中的总 ID。它不会添加相同的 ID 两次。
从我的代码(你可以做剩下的检查,比如用户是否在不喜欢的数组中,做一些事情等):
likeActivity: function (activityId) {
Activities.update(activityId,{
$addToSet: {
likers: this.userId,
}
});
},
unlikeActivity: function (activityId) {
Activities.update(activityId,{
$pull: {
likers: this.userId,
}
})
}
在我的助手中:
likeCount: function() {
return this.likers.length
}