- 使用 Apache Commons Lang 的 StringEscapeUtils:
import org.apache.commons.lang3.StringEscapeUtils;
private String escapeProcessName(String processName) {
return StringEscapeUtils.escapeJava(processName);
}
这种方法会转义 Java 语言中的特殊字符,但可能不足以完全防止命令注入。
- 使用 Java 的 Pattern.quote() 方法:
import java.util.regex.Pattern;
private String escapeProcessName(String processName) {
return Pattern.quote(processName);
}
这会将整个字符串作为字面量处理,但可能会影响命令的执行。
- 使用白名单方法:
private String escapeProcessName(String processName) {
return processName.replaceAll("[^a-zA-Z0-9_.-]", "");
}
这种方法只允许字母、数字、下划线、点和连字符,删除所有其他字符。
- 使用 ProcessBuilder 而不是 Runtime.exec():
private Process createProcess(String processName) throws IOException {
List<String> command = Arrays.asList("ps", "aux");
ProcessBuilder pb = new ProcessBuilder(command);
pb.redirectErrorStream(true);
return pb.start();
}
然后在读取输出时过滤包含 processName 的行。这种方法避免了直接在命令中包含用户输入。
- 使用第三方库如 Google Guava 的 CharMatcher:
import com.google.common.base.CharMatcher;
private String escapeProcessName(String processName) {
return CharMatcher.anyOf("$&;`()\"'|<>").replaceFrom(processName, "");
}
这种方法类似于正则表达式的方法,但可能更高效。
- 对于远程 Linux 系统,考虑使用 pkill 命令:
private String createCommand(String processName) {
return String.format("pkill -f %s", processName);
}
pkill
命令会自动处理大多数特殊字符。
- 使用 Java 9+ 的 ProcessHandle API:
private List<ProcessHandle> findProcesses(String processName) {
return ProcessHandle.allProcesses()
.filter(ph -> ph.info().command().map(cmd -> cmd.contains(processName)).orElse(false))
.collect(Collectors.toList());
}
这种方法完全避免了使用 shell 命令,但仅适用于本地进程。