从库输入构建的不安全的 shell 命令¶
ID: js/shell-command-constructed-from-input
Kind: path-problem
Security severity: 6.3
Severity: error
Precision: high
Tags:
- correctness
- security
- external/cwe/cwe-078
- external/cwe/cwe-088
Query suites:
- javascript-code-scanning.qls
- javascript-security-extended.qls
- javascript-security-and-quality.qls
使用导出函数的输入动态构建 shell 命令可能会无意中改变 shell 命令的含义。使用导出函数的客户端可能会使用包含 shell 以特殊方式解释的字符的输入,例如引号和空格。这会导致 shell 命令行为异常,甚至允许恶意用户在系统上执行任意命令。
建议¶
如果可能,请使用安全的 API(例如 child_process.execFile
)以数组形式将动态参数提供给 shell,以避免 shell 解释。
如果以单个字符串形式提供参数,请避免简单地在空格处拆分字符串。参数可能包含带引号的空格,导致它们被拆分为多个参数。使用类似 shell-quote
的库来解析字符串,而不是将其解析为参数数组。
或者,如果命令必须由 shell 解释(例如,因为它包含 I/O 重定向),则可以在将输入嵌入命令之前使用 shell-quote
转义输入中的任何特殊字符。
示例¶
以下示例显示了动态构建的 shell 命令,该命令从远程 URL 下载文件。
var cp = require("child_process");
module.exports = function download(path, callback) {
cp.exec("wget " + path, callback);
}
但是,如果输入包含空格或 shell 以特殊方式解释的其他特殊字符,则 shell 命令将无法按预期工作。
更糟糕的是,客户端可能会传入用户控制的数据,而不知道输入被解释为 shell 命令。这可能会允许恶意用户提供输入 http://example.org; cat /etc/passwd
,以执行命令 cat /etc/passwd
。
为了避免这种潜在的灾难性行为,请将导出函数的输入作为不会被 shell 解释的参数提供。
var cp = require("child_process");
module.exports = function download(path, callback) {
cp.execFile("wget", [path], callback);
}
再举一个例子,考虑以下代码,它与前面的示例类似,但将 wget
的输出管道到 wc -l
,以计算下载文件的行数。
var cp = require("child_process");
module.exports = function download(path, callback) {
cp.exec("wget " + path + " | wc -l", callback);
};
在这种情况下,使用 child_process.execFile
不是一种选择,因为需要 shell 来解释管道运算符。相反,您可以在将输入嵌入命令之前使用 shell-quote
转义输入。
var cp = require("child_process");
module.exports = function download(path, callback) {
cp.exec("wget " + shellQuote.quote([path]) + " | wc -l", callback);
};
参考¶
OWASP: 命令注入.
npm: shell-quote.
常见漏洞枚举:CWE-78.
常见漏洞枚举:CWE-88.