本文介绍如何在 Java 中安全地对用户输入字符串进行手动转义,使其可安全传递至 Bash Shell 执行,重点解决分号(;)、管道(|)、重定向(>、
本文介绍如何在 java 中安全地对用户输入字符串进行手动转义,使其可安全传递至 bash shell 执行,重点解决分号(`;`)、管道(`|`)、重定向(`>`、`
在 Java 中将用户输入拼接到 Bash 命令中执行(例如通过 Runtime.exec() 或 ProcessBuilder)时,若未对特殊字符做严格转义,极易引发命令注入漏洞——攻击者可通过输入 ; rm -rf / 或 $(rm -rf /) 等恶意片段劫持整个 Shell 行为。因此,手动转义必须精准、可预测,且避免依赖正则引擎引入额外复杂性。
✅ 推荐做法:使用 String.replace()(非正则版),而非 replaceAll()
replace(CharSequence target, CharSequence replacement) 是字面量替换,语义清晰、无正则元字符干扰,是安全转义的首选:
public static String escapeForBash(String input) {
if (input == null) return "";
return input.replace("\", "\\")
.replace(";", "\;")
.replace("|", "\|")
.replace("&", "\&")
.replace("$", "\$")
.replace("`", "\`")
.replace(""", "\"")
.replace("'", "\'") // 注意:单引号内无法转义单引号,需先闭合再拼接(见下文)
.replace("", "\>")
.replace("(", "\(")
.replace(")", "\)")
.replace("[", "\[")
.replace("]", "\]")
.replace("{", "\{")
.replace("}", "\}")
.replace(" ", "\ ");
}
⚠️ 关键注意事项:
- 单引号 ' 的特殊性:Bash 中单引号内部完全禁止转义(包括 ' 无效)。正确处理方式是:'text' + ''' + 'more' → 即先闭合单引号,拼接一个转义的单引号 '',再开启新单引号。若必须用单引号包裹整个字符串,更安全的做法是改用双引号包裹,并对双引号和 $、` 等转义;或统一使用 ProcessBuilder(推荐,见下文)。
- 反斜杠 必须最先转义:否则后续替换会破坏已生成的转义序列(如 \; 中的 若未提前处理,可能被后续规则误匹配)。
- 空格转义不可省略:防止参数被 Bash 拆分为多个词,导致命令逻辑错误。
? 更优实践:避免字符串拼接 Shell 命令
上述转义仅适用于简单场景。生产环境强烈推荐使用 ProcessBuilder,它天然规避 Shell 解析层,无需手动转义:
List<string> command = Arrays.asList("ls", "-l", userProvidedPath); // userProvidedPath 可含空格、分号等
ProcessBuilder pb = new ProcessBuilder(command);
pb.inheritIO();
Process p = pb.start();</string>
此时 userProvidedPath 作为独立参数直接传入 ls 进程,Bash 完全不参与解析,零注入风险。
? 总结:
- 对于必须走 bash -c "..." 的遗留场景,优先用 replace() 链式转义,并严格按 → ; → | → & → $ → ` → " → → ` `(空格)等顺序处理;
- 单引号内容应避免动态拼接,或改用双引号+转义策略;
- 终极安全方案是弃用 Shell 字符串拼接,转向 ProcessBuilder 或 ProcessBuilder.command(...) —— 这不是“更麻烦”,而是消除整个攻击面的根本解法。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











