【问题标题】:Making Vote System Secure Meteor.Methods使投票系统安全 Meteor.Methods
【发布时间】:2016-02-20 09:18:31
【问题描述】:

我正在尝试实现一个安全的投票系统,并且不能使用来自客户端控制台的 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()}
        }); 
  },
    });

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

【问题讨论】:

    标签: meteor meteor-methods


    【解决方案1】:

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

    让我们首先扩展 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); 
    });
    

    more on this technique

    现在让我们采用第一种方法:

    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 = Meteor.userId(); 它对我有用,为什么它不使用 var userId = this.userId(); ???感谢您的帮助!
    • 如果我尝试为我的第二次调用 argumentVoteYesElse 实现相同的逻辑,我会收到 Cannot call method 'indexOf' of undefined 错误。猜猜它的原因是我在创建新帖子时没有插入投票?当有人第一次点击一个新帖子并想要投票给这个帖子时,会出现错误消息。所以在尝试 post.votedUp.indexOf(userId) 时没有 votedUp。我现在该怎么办??我现在为帖子添加了投票按钮。如果第一次单击 voteDown 然后更改为 voteUp,也会出现同样的问题。
    • 我猜现在问题出在我的逻辑上。因为现在我可以在我的控制台中调用'voteUpYes'。我的分数增加了 2 并设置了 votedUp:Meteor.userId()。在此之后我可以调用'voteYesElseElse' 并减少计数器1 和votedUp: Meteor.userId() 被删除。然后我可以再次拨打'voteUpYes' 等等。没有限制..这个问题真的把我搞砸了。 =/
    • 除了指出您需要对称性之外,我不确定我能否帮助您。
    【解决方案2】:

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

    【讨论】:

    • 是的,但我不知道如何获取 Meteor.userId() 的数组值?类似 db.arguments.find({_id:currentArgumentId......?});如果 Meteor.userId(); 我必须检查数组已经存在,但我如何获得价值?我尝试了var votedUpMeteorUser = Arguments.findOne(currentArgumentId); if (Meteor.userId()!=null && votedUpMeteorUser.votedUp != Meteor.userId()) {.....} 之类的东西,但这不起作用
    • 你应该在服务器上使用 this.userId。
    【解决方案3】:

    我之前也想过同样的事情,我发现解决方案是仅使用您未从客户端传递的 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
    }
    

    【讨论】:

      猜你喜欢
      • 2019-02-26
      • 2012-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-08
      • 1970-01-01
      • 2011-07-28
      • 1970-01-01
      相关资源
      最近更新 更多