0

我正在尝试实现一个安全的投票系统,并且不能使用来自客户端控制台的 Meteor.call() 进行更改。每个人都可以在登录后对一些帖子进行上下投票。但每个用户和帖子一次只能投票一次。

只有我的客户端我得到了这样的东西:

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()}
        }); 
  },
    });

问题是我如何确保这个安全,例如如果有人调用 aMeteor.call('argumentvoteYes', "someID" , {$inc: {score:2}});它将增加 2 的分数。如果用户调用它两次,投票将增加 4。有什么方法可以安全地做到这一点?

4

3 回答 3

1

您不必担心该方法会产生额外的增量,因为您的方法只接受一个参数。但是,您确实需要防范其他黑客攻击:

让我们首先扩展Match对象,以便我们可以检查 an_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 }
        });
      }
    }
  },
于 2016-02-18T21:30:39.327 回答
1

您需要检查用户是否在服务器上的 votedUp/down 数组中。您拥有正确的客户端逻辑,因此只需在服务器上进行实际更新之前应用相同的逻辑。

于 2016-02-18T17:06:42.350 回答
0

我之前也想过同样的事情,我发现解决方案只是使用一个你没有从客户端传递的 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
}
于 2016-02-20T01:18:31.420 回答