Meteor 如何防止通过控制台修改集合以进行其他安全的更新操作?

Meteor 如何防止通过控制台修改集合以进行其他安全的更新操作?,meteor,Meteor,我对Meteor还很陌生,只是想弄清楚Meteor的安全性 我正在编写一个测验应用程序,允许登录用户保存他们的分数。我创建了一个由用户id和分数数组组成的集合。我公开推送新分数的方式是服务器端的一种方法: Meteor.methods({ 'pushScore' : function(playerId, playerScore) { UserScores.upsert({ userId : playerId}, {$push : {scores : playerScore}});

我对Meteor还很陌生,只是想弄清楚Meteor的安全性

我正在编写一个测验应用程序,允许登录用户保存他们的分数。我创建了一个由用户id和分数数组组成的集合。我公开推送新分数的方式是服务器端的一种方法:

Meteor.methods({ 
  'pushScore' : function(playerId, playerScore) {
    UserScores.upsert({ userId : playerId}, {$push : {scores : playerScore}});
  }
});
我从客户端单击按钮调用该方法,如下所示:

if (Meteor.userId()){
  Meteor.call('pushScore', Meteor.userId(), Session.get("score"));
}
我有以下关注:

  • 显然,用户可以在“会话”中操纵分数值并欺骗系统。在进行测验时,有什么替代安全机制可以跟踪跑步成绩
  • 另一个可能是更大的担忧。我如何防止用户仅仅对我的方法“pushScore”启动控制台调用,然后再次通过添加(比如100分)来欺骗系统
  • 我在这里设计的方式有内在的缺陷吗
这只是一个示例应用程序,但我可以很容易地想象一个真实世界的场景,它可以模拟这一点。在这种情况下,什么是最佳实践

提前谢谢


干杯。

简而言之,您的问题有两种常见的解决方案:

  • 如果您使用的是Meteor.method,那么不要在Meteor.call中传递任何参数,服务器可以并且应该收集它计划在服务器端插入/更新的数据

  • 您可以使用collection“allow”方法向集合添加验证函数,以验证来自客户端的任何更新,在这种情况下,您不需要Meteor.method,只需从客户端更新并在服务器端验证即可

  • meteor中的安全性(插入/更新/删除操作)与任何其他框架中的安全性工作方式相同:在执行用户采取的操作之前,确保用户有权执行该操作。在Meteor中,安全性可能看起来是一个弱点,但它并不比其他框架更容易受到影响(不过,通过控制台在Meteor中利用它更容易)

    最好的解决方法可能因情况而异,但这里有一个例子:如果用户发布帖子,用户应该获得5分。下面是一个糟糕的解决方法:

    if(Meteor.isClient){
    //插入柱和增加点。
    insert({userId:Meteor.userId(),post:“post.”)
    Meteor.users.update(Meteor.userId(),{$inc:{'profile.points':5}})
    }
    if(Meteor.isServer){
    允许({
    插入:函数(用户ID、文档){
    检查(文件{
    _id:String,
    userId:String,
    帖子:String
    })
    //你必须做你自己。
    如果(doc.userId!=userId){
    返回错误
    }
    返回真值
    }
    })
    Meteor.users.allow({
    更新:函数(用户名、文档、字段名、修饰符){
    检查(修改器{
    $inc:{
    “profile.points”:编号
    }
    })
    如果(修饰符$inc['profile.points']!=5){
    返回错误
    }
    返回真值
    }
    })
    }
    
    是什么让它变得糟糕?用户可以在不发布帖子的情况下增加分数。这里有一个更好的解决方案:

    if(Meteor.isClient){
    //插入柱和增加点。
    call('postandincrese',{userId:Meteor.userId(),post:“The post.”
    }
    if(Meteor.isServer){
    流星法({
    postAndIncrease:函数(post){
    支票(邮寄){
    userId:String,
    帖子:String
    })
    //你必须做你自己。
    if(post.userId!=this.userId){
    返回错误
    }
    员额。插入(员额)
    Meteor.users.update(this.userId,{$inc:{'profile.points':5}})
    }
    })
    }
    
    好多了,但还是不好。为什么?由于延迟(post是在服务器上创建的,而不是在客户机上创建的)。这里有一个更好的解决方案:

    if(Meteor.isClient){
    //插入柱和增加点。
    insert({userId:Meteor.userId(),post:“post.”)
    }
    if(Meteor.isServer){
    允许({
    插入:函数(用户ID、文档){
    检查(文件{
    _id:String,
    userId:String,
    帖子:String
    })
    //你必须做你自己。
    如果(doc.userId!=userId){
    返回错误
    }
    返回真值
    }
    })
    Posts.find().观察({
    新增:职能(岗位){
    //添加新帖子后,用户将获得分数。
    Meteor.users.update(post.userId,{$inc:{'profile.points':5}})
    }
    })
    }
    

    这个解决方案唯一的缺点是点增量的延迟,但这是我们必须忍受的(至少目前是这样)。在服务器上使用observe也可能是一个缺点,但我认为您可以通过使用包收集挂钩来获得通过。

    正如@Peppe所建议的,您应该以某种方式将逻辑移到服务器上。Meteor安全(以及一般的web安全)的主要规则是

    你不能信任客户。 原因是您已经提到过:如果客户端可以做一些事情,那么就无法阻止恶意用户从浏览器控制台做同样的事情,甚至无法阻止他编写自己的恶意客户端来利用漏洞

    在您的情况下,这意味着如果客户端能够为分数添加分数,那么用户也可以这样做,无论您采用什么安全措施。您可以使这变得或多或少困难,但您的系统存在无法完全关闭的设计泄漏

    因此,唯一的防弹解决方案是让服务器决定何时分配点。我假设在一个测验应用程序中,当用户选择一个问题的正确答案时,他会得到分数。所以,不是切