【问题标题】:Meteor: How to prevent client from accessing methodsMeteor:如何防止客户端访问方法
【发布时间】:2015-11-22 20:23:23
【问题描述】:

所有流星方法都可以从客户端和服务器端以相同的方式调用。

假设用户知道或可以预测服务器上的所有方法名称,那么他就可以调用它们并使用它的结果,但是他想要的。

示例: 执行跨域http请求和返回响应的方法可以通过调用大量数据Meteor.call(httpLoad, "google.com");来使服务器过载,或者如果客户端知道文档_id@987654322,可以使用从mongo加载数据的方法访问数据库文档@。

那么,如何避免这种情况,是否有比Meteor.methods({...}) 更好的方式来存储仅服务器功能?

【问题讨论】:

    标签: javascript node.js mongodb methods meteor


    【解决方案1】:

    Meteor 方法被设计成可以从客户端访问,如果你不想这样,你只需要在服务器上定义一个普通的 javascript 函数。一个非常基本的例子是:

    server/server.js:

    someFunction = function(params) {
        console.log('hello');
    }
    

    只要它在服务器文件夹中,就无法从客户端访问该功能。


    对于咖啡脚本用户,每个文件在技术上都是一个单独的范围,因此您必须使用@ 定义一个全局变量,例如

    @someFunction = (params) ->
        console.log 'hello'
    

    或者如果您想将函数范围限定为一个包:

    share.someFunction = (params) ->
        console.log 'hello'
    

    如果您有需要从客户端访问但仅限管理员用户访问的方法,则需要在流星方法定义的开头添加这些检查:

    Meteor.methods({
        'someMethod': function(params) {
            var user = Meteor.user();
            if (user && (user.isAdmin === true)) {
                // Do something
            } else {
                throw new Meteor.Error(403, 'Forbidden');
            }
        }
    });
    

    我不会保证这个例子的安全性——这只是一个例子——但希望它能让你了解如何保护你的方法。

    编辑:注意到使用if (Meteor.isServer) { ... } 条件的其他答案。请注意,如果您在客户端上也可以访问 inside 方法,那么用户仍然可以看到您的服务器代码,即使他们无法运行它。这对您来说可能是也可能不是安全问题 - 如果您在可以从客户端访问其代码的方法中硬编码任何第 3 方 API 凭据或任何类型的敏感数据,请务必小心。如果客户端不需要该方法,最好只使用普通的JS函数。如果您使用 isServer 条件包装整个 Meteor.methods 调用,则代码将仅在服务器上,但仍可以从客户端调用。

    【讨论】:

    • Meteor 方法可以很容易地与回调链接起来,这可能不适用于常规函数,因为“代码必须在纤维内运行”。到目前为止,无论如何这是最好的答案;)
    • 取决于您要实现的目标。据我所知,如果您在服务器上使用方法回调,那么您只会返回“未定义”。该方法的其余部分将运行,但您不会得到返回的结果。如果你需要返回一些东西,那么你需要同步运行该方法(例如,没有回调),所以它会返回一个值或抛出一个错误。
    【解决方案2】:

    正如其他答案中正确指出的那样,您的方法将始终可以从客户端访问(按设计)。然而,有一个简单的解决方法来检查调用是来自客户端还是来自服务器。如果你做一个

    if ( this.connection == null )
    

    如果该方法是从服务器调用的,这将是return true。像这样,您可以将方法主体执行限制为“安全”调用。

    【讨论】:

    • 然后我会将if(this.connection == null) 中的所有内容用if(Meteor.isServer) 包装起来,以防止客户端模拟和控制台错误。
    • 我已经尝试了两次这种方法,而且每次服务器代码调用 Meteor 方法时,它仍然将客户端连接传递给它。例如,如果我在 Accounts.onCreateUser 中调用 Meteor.call('sendMail', ...),它只在我的 server 文件夹中,它会将实时连接传递给 Meteor 方法。我注意到其他 Meteor 方法在尝试调用“仅服务器”Meteor 方法时会做同样的事情。唯一一次没有连接是当我尝试从 Meteor shell 调用它时。有什么想法吗?
    • 是的。如果来自客户端 this.connection 的呼叫将不是 undefined。查看此以获取更多信息:themeteorchef.com/recipes/…
    • 知道了!感谢您的链接。我想要制作仅限服务器的 Meteor 方法的主要原因是它们可以异步调用,这对于解除阻塞像 Email.send() 这样的仅限同步的方法很有用,这将阻塞你的客户端。因此,我发现异步调用某些同步方法的解决方案是将它们包装在 Meteor.setTimeout 集合中以供以后任何时间使用。这将从事件队列中删除调用并允许客户端继续。如果您不需要立即调用该函数(例如发送电子邮件),则效果很好。
    • 确实,Meter.setTimeout 周围有一个延迟为 0 的包装器,这将完全按照您所说的进行:将其从事件队列中删除。它被称为Meteor.defer()。以防万一你还没有偶然发现它..
    【解决方案3】:

    我认为这个页面解释了它:http://meteortips.com/first-meteor-tutorial/methods/

    我在引用:

    “更安全的做法是将这些函数移到isServer条件中,意思是:

    数据库代码将在服务器的可信环境中执行。 用户将无法从控制台内部使用这些功能,因为用户无法直接访问服务器。

    在isServer条件里面,写下:

    Meteor.methods({
       // methods go here
    });
    

    这是我们将用来创建方法的代码块。”

    等等。我希望这会有所帮助。

    【讨论】:

    • “用户将无法从控制台内部使用这些功能”,很抱歉,但是......他们可以。 evernote.com/shard/s244/sh/a96eb058-8b6e-4f71-85b0-2b400a392914/…
    • 糟糕,那页面一定是错误的,对不起!
    • 你都对,isServer 包装器所做的只是在服务器上定义方法,因此您将无法读取该方法的代码,但您仍然可以从客户端,从服务器返回结果。您可能在客户端定义方法的原因是为了乐观 UI,因此您可以在客户端上运行该方法的简化版本并立即更新 UI/minimongo,但随后服务器将返回 REAL 结果,如果它没有'不匹配,minimongo / UI 将被更新以反映这一点。
    • 这很有趣,听起来像编程在线游戏,玩家在游戏中得到即时反应,然后他的计算最终被服务器结果纠正。
    【解决方案4】:

    通过适当的应用程序设计,您不必关心请求是通过 Web UI 还是通过在控制台窗口中键入的内容。

    基本上,不要在 Meteor.methods 中放置通用的、值得滥用的函数、实施合理的访问控制、速率限制和/或记录任何可能存在问题的内容。

    Meteor.methods 中定义的任何服务器端函数都可以通过this.userid 访问当前用户ID。此用户 ID 由 Meteor 提供,而不是客户端 API 参数。

    由于 Meteor Method 服务器端代码知道登录状态和用户 ID,因此它可以在决定执行用户要求它执行的操作之前执行您想要的所有检查和速率限制。

    你如何限制速率?我最近没有为此寻找模块。在基本 Meteor 中,您将为仅在服务器端可访问的用户操作添加 Mongo 集合。在通过 Meteor 方法到达的每个请求上插入带有时间戳的用户 ID 特定数据。在执行服务器方法代码中的请求之前,请执行 Mongo 查找在相关时间段内从此用户 ID 发生了多少此类操作。这是一个小工作并且会产生一些开销,但是通过服务器范围的下划线样式的去抖动来限制速率的替代方案使攻击者滥用和拒绝服务的功能开放。

    【讨论】:

    • 尚未对其进行测试,但 meteorhacks:sikka 是流星方法的速率限制器(请参阅atmospherejs.com/meteorhacks/sikka)。我想我在某处读到他们将实现类似的东西作为流星核心的一部分,但我不确定是否/何时会。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-21
    • 1970-01-01
    • 2015-08-18
    • 1970-01-01
    • 2014-04-28
    • 2022-01-01
    相关资源
    最近更新 更多