node-open 是一个 npm 包,可以使用系统默认关联的方式打开 uri 和本地文件。从 commit 日志和 npm 发布时间来看,node-open 包似乎已经停止维护好几年了:
- https://www.npmjs.com/package/open
- https://github.com/pwnall/node-open
另外作者的用户名 pwnall 让我一度误认为是 pwnallthethings 的马甲,居然还是位 Chrome 的开发成员。

这个包的源码非常短,问题很明显: https://github.com/pwnall/node-open/blob/master/lib/open.js#L58
var exec = require('child_process').exec
...
return exec(opener + ' "' + escape(target) + '"', callback);
...
function escape(s) {
return s.replace(/"/g, '\\\"');
}
虽然用了所谓的 escape 函数把双引号闭合了回去,但是这毕竟是 child_process.exec,是支持 shell 语法的。例如在 mac 系统下即可在 url 中使用 反引号、\$()、\${} 等特殊字符执行命令、获取环境变量。真是一股浓浓的 Damn Vulnerable Web Application 风味,还是入门级的难度。使用 node-open 打开外部不受信任的 url 等同于 php 里直接拼接 system 的参数。
那么他在真实环境中的影响有多大呢?
这是 2018 年 2 月 27 日的统计数据:
Stats
- 28,381 downloads in the last day
- 476,031 downloads in the last week
- 1,925,595 downloads in the last month
虽然下载量和依赖量很大,但并不能说明这就是一个影响范围很大的安全问题——child_process 这个模块每一个 node 发行包都有,就直接搞个大新闻说 Node.js 不能用?
使用系统关联工具打开 url 的场景多适用于桌面应用,因此不大可能会使用这个模块。但有一些桌面工作流可能会出现使用 RPC 接口的情况。
Macaw 是一款所见即所得网页编辑器,支持在浏览器中实时预览(livereload):http://macaw.co/
在 Macaw.app/Contents/www/thirdparty/preview/index.js 中打开了两个服务器:
// defaul ports for server and LR
var defaults = { livereload: 15729, port: 5353 };
一个是 livereload 的 WebSocket,另一个是 JSON RPC 的服务。有一个支持传入参数拼接后打开浏览器的接口:
//open default browser
app.get('/openbrowser/:path/:file', function(req, res) {
var file = req.param('file');
var path = req.param('path');
var callback = function() {
open('http://localhost:'+app.get('port')+'/'+file);
};
setWatch(path, callback);
// return 200 OK
res.send(200);
});
这里的 file 参数由外部 HTTP 请求传入,直接拼接到了 url 中。简单地使用 shell 脚本即可被执行:
import requests
requests.get('http://192.168.1.100:5353/openbrowser/aaa/`echo 1>${PWD}tmp${PWD}1`')
安装了这个编辑器的前端开发者万万没想到,这个软件居然就这样成了一个赤裸裸的后门。
Macaw 对此问题的答复是,由于这款软件已经被 InVision 收购,1.6 将成为最终版本,不再修复 bug。
鉴于 node-open 这个显而易见的问题和停止维护的状态,请考虑使用替代方案。例如 opn:https://www.npmjs.com/package/opn