【问题标题】:Securing my denormalized Meteor rating system保护我的非规范化 Meteor 评级系统
【发布时间】:2014-11-14 22:18:22
【问题描述】:

这是一个艰难的(对我而言)罗嗦的:

我正在接受整个 Mongo 非规范化的事情。我创建了一个评分系统,用户可以对彼此的视频进行评分。为了获得视频的平均分数,每次用户“评论”它(使用流星.methods upsert )。当然,一个条目的平均分数是所有这些评分的总和除以评论总数。无论如何,我都会将每条评论记录在一个单独的集合中。

我的问题是......我不知道如何安全地写这个。确实没有什么可以阻止某人将大于 10 或小于 0 的数字添加到总和(或重复添加可接受的数字)。

你能帮忙吗?也许如果我说“如果您尝试将评论总和更新为(在条目文档中)的新数字不等于存储在评论集合中的该条目的所有评论的总和,则抛出错误。 ..加上你的最新分数。”但如果这是正确的,那到底是怎么写的?

这是共享的客户端/服务器代码:

//update reviews
Meteor.methods({
  reviewUpsert: function(id, doc) {
    if (!this.userId) {
      throw new Meteor.Error(403, "You must be logged in to do that.");
    }
    if (Meteor.users.findOne(this.userId).emails[0].verified !== true) {
      throw new Meteor.Error(403, "Your email must be verified to review. Check your email inbox.")
    }
    if (Meteor.user().status === "suspended") {
      throw new Meteor.Error(403, "Cannot perform this action while account is suspended.")
    }
    var review = Reviews.findOne(id);
    if (review && doc.reviewer !== this.userId) {
      throw new Meteor.Error(403, "You don't own that review.");
    }
    if (doc.reviewer !== this.userId) {
      throw new Meteor.Error(403, "Cannot create a review for someone else.");
      // alternatively, just set doc.owner = this.userId
    }
    Reviews.upsert(id, doc);
  }
});

//update entry score
Meteor.methods({
    entryScoreUpdate: function(id, doc) {
        Entries.update(id, doc);
    }
});

这是相关的客户端代码:

  Meteor.call('reviewUpsert',
    Reviews.findOne({unique_review: reviewer_and_entry}, {}, function(err, result){
      if (result) {
        return result._id;
      }
      if (!result) {
        return null;
      }
    }),
    {date: new Date(), reviewer: Meteor.userId(), entry: Session.get('entryId'), title: entrytitle.title, unique_review: reviewer_and_entry, reviewername: Meteor.user().username, review: reviewfield, score: parseInt(scorefield)}, function(err){
      if (err)
        Alerts.add('Review error: ' + err.reason, 'warning');
      else {
          var reviewAdd = parseInt(scorefield) - lastscore;
          Meteor.call('entryScoreUpdate',         
            {_id: Session.get('entryId')}, {$inc: {reviewsum: reviewAdd, reviewcount: incCount}},
            function(err){
              if (err)
                Alerts.add('Review error: ' + err.reason, 'warning');
              else {
                  var entryforavg = Entries.findOne(Session.get('entryId'));
                  Meteor.call('entryScoreUpdate',         
                    {_id: Session.get('entryId')}, {$set: {avgScore: Number(((entryforavg.reviewsum/entryforavg.reviewcount)*10).toFixed(2))}},
                    function(err){
                      if (err)
                        Alerts.add('Review error: ' + err.reason, 'warning');
                      else {
                        Alerts.add('Review has been updated.', 'success'),
                        Session.set("formStatus", 'oldForm');
                      }
                    }
                  );
              }
            }
          );
      }
    }
  ); 

【问题讨论】:

    标签: javascript mongodb security meteor denormalization


    【解决方案1】:

    这个怎么样:

    Meteor.methods({
        reviewUpsert : function(id, doc){
            ...
            if( (doc.rating > 10) || (doc.rating < 0) ){
                throw new Meteor.Error( ... )
            }
        }
    })
    

    至于阻止同一用户重复输入评分,您将必须跟踪哪些用户对哪些视频进行了评分并更新他们的评分,而不是简单地盲目添加新评分。

    【讨论】:

    • 感谢这部分。我在上面的代码中跟踪用户评分,但为了获得平均值并显示这些平均值的反应列表,我不得不在视频文档中复制它。为此,我必须允许用户访问视频文档。这就是安全问题开始的地方。除非您说要将每个评分存储在视频文档的数组中,并且根本没有一个仅用于评分的集合。
    • 也许在您的评分集合中,您还可以包含与每个评分相关联的用户 ID?这通常是我将标记放在白板上并找出哪种解决方案最糟糕的地方。 ;)
    【解决方案2】:

    我终于明白了。我不需要在客户端调用 entry.update 作为它自己的 Meteor.method 。我可以在“reviewsupsert”方法中在服务器上运行 Entries.update。这样一来,我就不会真正授予用户编辑其他用户视频的权限。他们只是编辑他们的评论,服务器会编辑视频的平均值。

    【讨论】:

      猜你喜欢
      • 2020-04-06
      • 2016-01-31
      • 2017-01-27
      • 2010-10-22
      • 1970-01-01
      • 2012-12-30
      • 2020-05-21
      • 1970-01-01
      • 2013-08-21
      相关资源
      最近更新 更多