flawopen.com/Command Injection/Java Runtime.exec()
Java Runtime.exec() 能防止 Command Injection 吗?
Runtime.exec(String) 不会隐式启动 shell,因此 shell 运算符不会自动按 shell 语法解释。但该字符串仍会拆分为程序和参数,不可信文本仍可能改变目标程序收到的参数。ProcessBuilder 能明确参数边界;仍需验证每个值,并限制可执行文件和允许的选项。
// 用户输入与命令字符串拼接 Runtime.getRuntime().exec( "approved-tool --input " + filename );
// 固定程序和独立参数;先验证filename String safeName = validateFilename(filename); new ProcessBuilder( "/opt/app/bin/approved-tool", "--input", safeName ).start();
Shell 注入与参数注入不同
从 Java 18 起,Oracle 因 Runtime.exec(String) 容易出错而将其弃用,并建议使用 exec(String[]) 或 ProcessBuilder。字符串重载按空白字符拆分命令,因此包含空格的路径等参数可能被拆开。 Runtime.exec(String) 不会隐式启动 sh 或其他 shell;Oracle 文档说明该单字符串重载会把命令字符串转换为参数数组。因此常见 shell 元字符不会作为 shell 语法处理,但输入仍有风险:分词仍可能产生额外参数,目标程序也可能把参数解释为选项。ProcessBuilder 接收由程序和参数组成的字符串列表;常见平台上每个元素都是一个参数边界。固定可执行文件,按目标程序预期语法验证值,并拒绝或安全处理看起来像选项的值。仅当目标程序文档保证支持时才使用 --。不要把不可信数据传给显式启动的 shell(例如 sh -c)。
常见问题
不安全。该重载降低了 shell 注入风险,但仍可能发生参数注入。目标程序可能将攻击者控制的输入解释为选项或文件名。使用固定可执行文件和独立参数的 ProcessBuilder,并按目标程序规则验证每个值。
不会。它构造程序和参数列表并启动进程,但不会检查它们是否安全或有效。应用程序仍需使用白名单和验证,并遵守目标程序记录的参数规则。