【问题标题】:Hide secret server code called from Meteor Methods隐藏从 Meteor 方法调用的秘密服务器代码
【发布时间】:2017-01-30 19:11:33
【问题描述】:

我正在努力思考如何在 Meteor Methods 中向客户端隐藏秘密服务器代码The docs seem to imply 以下是其完成方式的一般模式。 https://guide.meteor.com/structure.html#using-require

(请注意,根据文档,我使用 require 而不是 import,因为 import 不能在条件块中使用。)

首先,这是一个在名为 methods.js 的文件中定义的方法,并在客户端和服务器上都导入:

/* methods.js */

let ServerCode
if (Meteor.isServer) {
  ServerCode = require('/imports/server-code.js')
}

Meteor.Methods({
  'myMethodName': function() {
    // ... common code
    if (Meteor.isServer) {
      ServerCode.secretFunction()
    }
    // ... common code
  }
})

其次,这是/imports/server-code.js 中的秘密服务器代码,我试图不发送给客户端:

/* server-code.js */

class ServerCode {
  secretFunction() {
    console.log('TOP SECRET!!!!')
  }
}

const ServerCodeSingleton = new ServerCode()
module.exports = ServerCodeSingleton

但是当我检查发送到客户端浏览器的源时,我仍然看到我的秘密服务器代码被发送到客户端:

即使我进行生产构建,我仍然可以搜索并找到“绝密!!”细绳。我觉得我对 require 工作原理的理解过于天真,但 Meteor 文档让它看起来如此简单。那么隐藏从 Meteor Methods 调用的密码的正确方法是什么?

【问题讨论】:

    标签: javascript meteor require


    【解决方案1】:

    我想我终于想通了。

    简短的版本是,忽略这里所说的;我认为这是不正确的或至少具有误导性:

    https://guide.meteor.com/structure.html#using-require

    并按照这里所说的:

    https://guide.meteor.com/security.html#secret-code

    更长的解释是:在一个仅服务器文件中,import 密码并将其分配给一个全局变量。然后,在一个公共文件,使用isServer(或!isSimulation)有条件地引用该全局变量。

    所以我原来的例子可能会这样重写:

    /*   /imports/methods.js   */
    
    // Note: no conditional use of require this time
    
    Meteor.Methods({
      'myMethodName': function() {
        // ... common code
        if (Meteor.isServer) {
          ServerCode.secret() // <-- Defined as a global outside of this file!
        }
        // ... common code
      }
    })
    

    因此密码文件可能如下所示:

    /*   /imports/server-code.js   */
    
    class _ServerCode {
      secret() {
        console.log("Shhhhhh, I'm secret()!")
      }
    }
    // Here's the global variable:
    SecretCode = new _SecretCode()
    

    然后在 server-only 文件中,它可能看起来像这样:

    /*   /server/server-main.js   */
    
    import '/imports/secret-code' // <-- declare the global
    import '/imports/methods' // <-- use the global in here
    

    然后在 client-only 文件中可能如下所示:

    /*   /client/client-main.js   */ 
    
    import '/imports/methods'
    
    //...
    
    Meteor.call('myMethodName')
    

    现在客户端和服务器都可以在方法主体 (DRY) 中执行一些完全相同的代码,而一些密码可以是服务器专用的并赢得也不会发送给客户。不得不求助于使用全局变量有点烦人,但这也许是最干净的选择,直到出现支持内置延迟加载模块的更高级的 import 版本。

    【讨论】:

    • 无需在“共享”(同构)文件夹中创建Meteor.methods({/*...*/})Meteor.methods({/*...*/}) 仅在服务器上执行,必须放在 server 目录下,- 考虑到安全问题
    • 阅读methods docs。在客户端调用方法定义了 stub 函数。
    • 文档说 Meteor.methods “必须”放在服务器文件夹中。在这种情况下,存根函数不是空操作。它们具有立即(尽管可能是暂时的)副作用,可以补偿往返延迟。这就是 Optimistic UI 的全部意义所在。例如,在 To Do 教程中,新输入的 to-do 项可以在服务器看到插入之前立即出现在客户端上。在服务器确认或不确认新项目后,客户端会解决任何差异。至少这是我的理解。
    • “考虑到安全问题” - 因此您可以放置​​两个具有相同名称的方法 - 一个带有“秘密”代码的 server 目录,第二个带有存根“延迟补偿”的 client 目录" 代码。
    • 我不确定您在上一条评论中所断言的内容。但是将两个具有相同名称的相似方法放在两个不同的地方,这(由于乐观的 UI)除了服务器上的一些密码之外,大部分都做同样的事情,这违反了 DRY 原则。换句话说,您将在两个不同的地方维护类似的代码。查看我包含的安全链接。它几乎完全地谈到了我原来的问题。又来了:guide.meteor.com/security.html#secret-code
    【解决方案2】:

    编辑:忽略答案,不解决 OP 对 DRY 代码或乐观更新的渴望。

    默认情况下,Meteor 实现了一个关于文件的预加载方案。你的 methods.js 就是一个例子。

    如果文件位于名为“client”的文件夹下任何位置的目录中,则该文件仅提供给客户端。同样,“服务器”下的任何文件都只提供给该文件夹。这就是您确保文件仅提供给服务器的处理方式。

    正如您所发现的,“Meteor.isServer”构造仅限制环境中运行的内容,而不限制环境中提供的内容。

    我通常像这样实现 Meteor 方法:

    server/some/path/stuff.js:

    // this is only on the server
    Meteor.methods({
        'getStuff': function() {
            return "stuff";
        }
    });
    

    client/some/path/clientStuff.js:

    // this is only on the client, calling the server method
    Meteor.call('stuff', function(error, result) {
        if (error && error.reason) {
            alert(error.reason);
        }
        else {
            // use result
        }
    });
    

    关于require,你为什么要使用它?

    我看到您在 /imports 中有代码,Meteor 将其视为特殊的并且不会急切加载。这告诉我你明确地导入了这些东西。

    MDG 对目录结构、ES15 模块以及如何加载代码有一些强烈的建议,他们在这里详细介绍:

    https://guide.meteor.com/structure.html

    您会注意到他们不使用 require,并且指定模块的方式与您的做法不同。

    【讨论】:

    • 非常感谢您的回复。我知道推荐的目录结构,但是如果您在此处查看此链接:guide.meteor.com/structure.html#using-require 您会看到他们提到 require 作为有条件地拉入模块时的推荐选项。 (条件块中不允许“导入”。)
    • 此外,在基本的 To Do 教程 (meteor.com/tutorials) 中,Meteor 方法在 客户端和服务器上导入。这就是使 Optimistic UI 行为成为可能的方式。您实现 Meteor 方法的方式会阻止 Optimistic UI 效果。也许 Optimistic UI 和秘密服务器代码是相互排斥的,但我只是不明白为什么这些文档会让人觉得它们不是......
    • 啊,我明白你在做什么。我第一次不知何故错过了你的要求声明。好的,是的,阅读您提供的有关要求的链接,它看起来确实应该按照您的指示工作。抱歉,我错过了您的实际问题!
    • 据我所知,乐观 UI 并不依赖于在客户端包含服务器方法。发生这种情况是因为您在客户端上有 minimongo。如果您在服务器方法中进行插入,那么您会丢失它,但是您不能在客户端上进行插入/更新并将您的密码保留在服务器上吗?
    • @Mikkel 好吧,您的建议并不完全错误,但它不被认为是最佳实践:它可能违反 DRY(您要编写两次相同的代码),并引入安全问题(客户端可以进行恶意写入)。 Meteor 文档建议禁止在客户端上进行直接写入操作,而是建议将方法作为一种更安全的方法。换句话说,所有数据库写入操作都应该发生在方法主体中,并且方法应该在客户端和服务器上都导入。实际上,我只是想出了正确的方法,并且正在写一个答案。
    猜你喜欢
    • 1970-01-01
    • 2011-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-23
    • 1970-01-01
    相关资源
    最近更新 更多