node.js是否会增加跨连接共享数据的风险?

时间:2014-04-04 18:46:59

标签: node.js security

由于node.js是单线程的,并且许多请求使用异步回调或事件并行运行,并且任何一个请求都没有立即运行完成,因此来自一个http请求的进程最终会与其他请求共享变量请求,特别是在将数据存储在临时对象或函数/模块中的变量时?

例如,在php中,每个进程都获得它自己的线程并运行完成(阻止其他任何事情)。因此,无法跨连接/请求访问变量。

我试过谷歌搜索,但没有找到太多。这甚至是一个问题吗?是否有可能在不同(甚至相同)用户的个别请求之间无意中共享变量?

3 个答案:

答案 0 :(得分:2)

只有一种情况可能是一个问题:无意识的全局变量。

考虑以下Express路线:

app.post('/foo', function(req, res) {
    var user = req.cookies.user;
    token = generateToken(user);

    someAsyncOperation(user, req.body, function(err, result) {
        saveUser(token, result);
        res.send(result);
    });
});

你看到错误吗? user的作用域是函数,但token是一个隐式全局变量,将在所有请求中共享。

在这个例子中,假定的作者可能在user的定义之后使用逗号而不是分号(这将导致token正确确定范围)。不幸的是,他的手指向东北方向移动了一厘米,造成了一个容易错过的错误。

  • 请求A进来。user是从cookie加载的,某种令牌生成函数会创建一个对用户来说应该是唯一的令牌。
  • 异步操作排队,回调函数绑定到请求A的范围。
  • 异步操作需要一些时间,因此节点空闲。
  • 请求B进来。它在其范围内初始化一个新的user
  • 全局token使用请求B的令牌覆盖
  • 另一个异步操作排队等待B;节点再次闲置。
  • A&#s。async操作完成。
  • 糟糕, A的操作结果是使用B&B的令牌保存的,因为这是token最后设置的内容。
  • B&#39的异步操作完成,并将更多数据保存到B的令牌中。

在这种情况下,没有任何内容保存到A,并且两组数据都保存到B.这可能导致所有内容都出现奇怪的不一致,几乎不可能重现和调试,直到实际的经济损失。 (我是不是偶然发了B两个命令?)

好消息是很容易避免这个问题。使用strict mode。严格模式使得隐式全局变量ReferenceError除其他外。只需添加到js文件的顶部:

'use strict';

或使用参数运行节点:

--use_strict

启用严格模式后,您无法意外使用隐式全局,因此这不再是问题。局部变量和req / res对象是安全的;你可能遇到麻烦的唯一另一个领域就是你故意使用某种共享状态,但其他任何语言中的危险都是一样的。

答案 1 :(得分:1)

Javascript的工作方式与PHP不同。范围的行为完全不同,是防止问题成为问题的原因。

现实世界的比喻是想象你在一条线上有许多工作台。你的老板进来并在工作台上设置了一些项目。当你正在研究它时,他会在其他工作台上放置更多的物品。

在某个时刻,你会到达1号台的停靠点,在那里你必须等待。你搬到办公桌#2开始在那里工作。一旦你看到#1桌面再次准备就绪,你就可以去#1桌面再做一些工作。由于你有完全不同的办公桌,很难混淆。你只需要记住不要随身携带东西。 Node中的每个函数都有完全不同的范围,这使得节点很难弄清楚它正在做什么。

function object_init() { this.a = 'a'; return this }

function server_resp(req, res) {
    var obj = object_init();
    if ( req.changeTrue() ) {
         obj.a = 'b';
    }
    function test() {
        longOperation();
        console.log( obj.a );

    }

    test()
}

上面的代码片段是Node.js应用程序在非常高级别上可能发生的正常代码片段。大多数JavaScript应用程序都会有一段非常类似的代码片段。

您担心的是,在longOperation()之后,Node将返回到server_resp的错误实例。它没有发生的原因是因为每个请求都有自己的“工作台”。节点非常智能,可以从一个工作台移动到另一个工作台,而无需将物品从一个工作台搬到另一个工Node的工作是执行not carry。每个“板凳”都有自己的对象。每个“工作台”甚至都有自己的测试()。这是Javascript的工作方式,因为函数与对象密切相关。

PHP具有与javascript完全不同的内存和执行模型,这就是javascript可以安全地执行此操作的原因。 PHP更具程序性/ OOP,而javascript具有更多功能性。

这是节点如何工作的一般解释。表面下可能存在潜在的安全漏洞。根据内存模型和大小检查,整数溢出可能会重写内存库,让攻击者可以访问之前无法访问的作用域。糟糕的代码可能会扩大这个漏洞。对于普通代码,不同的请求之间的混合几乎不可能实现。

答案 2 :(得分:0)

如果你做得对,那真的不是一个问题,而且我并不是说这是轻率的。 :-)大多数语言都有全局范围或共享/可共享数据结构。即使使用线程操作,这也是一种风险,例如在线程环境中不正确地使用/实现Singleton。如果花时间了解Javascript的工作原理,并以反映这种理解的方式编写代码,那么这真的不应该是一个问题。

我建议您可以在搜索结果中对此进行大量讨论,鉴于网上有很多关于javascript的内容,应该让您放心,它不是“不是”。很大的问题。

花一些时间来了解(通过阅读和一些实验)关于范围和闭包在Javascript中的工作方式,你应该对此感到更加自在。

this question上排名前两位的答案应该有助于理解范围和闭包。除此之外,看一下构建在Express上的各种示例应用程序(并深入研究Express和Connect的代码),看看它们是如何实现的。