You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解决Coverity检测的OS命令注入问题:Java 11文件名验证优化

解决Coverity检测出的OS命令注入问题

问题背景

我正试图解决Coverity检测出的“OS_Command_injection”问题。文件名来自用户上传的Multipart文件,验证代码如下:

String filename = item.getName();
String regex = "^[a-zA-Z0-9_-]*$";
if(filename.matches(regex)) {                           
    if(filename.contains("../") || filename.contains("..") || filename.contains("./") || filename.contains("/")) {
        throw new BRException("Invalid filename");
    }
    Path filePath = Paths.get(location, filename);
    try ( OutputStream out = new FileOutputStream(filePath.toString()); ) {
        IOUtils.copy(stream, out);                              
        params.put("filename", filename);
        params.put("filePath", filePath);
    }
} else {
    throw new FSException("filename is Invalid");
}

后续调用Shell脚本进行病毒扫描时触发了OS命令注入告警,scanFile方法的相关代码(编辑后)如下:

scanScriptPath = "/scantool/scan.sh"; // 解析为shell脚本路径

StringBuilder scriptNfile = new StringBuilder("").append(scanScriptPath.toString()).append(" ").append(filePath.toString());

String[] cmd = {"sh","-c",scriptNfile.toString() };

ProcessBuilder pb = new ProcessBuilder(cmd);    // OS_Command_Sink              
Process proc = pb.start();
proc.waitFor();

Coverity错误信息:

OS Command Injection (OS_CMD_INJECTION)7. os_cmd_sink: Calling scanFile. Passing the tainted value filename to the process-invoking API may allow an attacker to modify the intention of the command. (The virtual call resolves to com.xyz.scanFile(java.lang.String, java.lang.String, java.lang.String)

已通过正则验证文件名并检查路径遍历字符,但问题仍未解决,请问还遗漏了什么?


问题根源

当前命令执行方式存在核心风险:

  • 使用sh -c拼接命令字符串:这种方式会让shell解析整个命令串,即便文件名符合正则,只要filePath包含shell特殊字符(如空格、;、&、$等),攻击者就能构造恶意文件名注入额外命令。Coverity的污点分析会标记这种拼接方式为高风险,因为输入被当作shell命令串的一部分,本质上还是存在注入可能。
  • 冗余的路径检查:正则^[a-zA-Z0-9_-]*$已经排除了/、..等字符,后续的contains检查完全多余,不是问题核心。

解决方案

彻底规避命令注入的关键是避免拼接命令字符串,改用参数化传递:

修改后的scanFile代码

scanScriptPath = "/scantool/scan.sh"; // 脚本路径

// 直接将脚本和文件路径作为独立参数传入,不拼接字符串
String[] cmd = {scanScriptPath.toString(), filePath.toString()};

ProcessBuilder pb = new ProcessBuilder(cmd);
Process proc = pb.start();
proc.waitFor();

原理说明

ProcessBuilder会把数组中的每个元素当作独立的命令/参数,不会经过shell解析。脚本scan.sh会直接将filePath作为第一个参数接收,彻底避免shell对特殊字符的解析,从根源上杜绝命令注入风险。同时保留原有的文件名正则验证,确保文件名合法。

额外优化建议

  1. 移除冗余的路径检查代码,正则已限制文件名仅含合法字符。
  2. 使用Java NIO的Files.copy替代FileOutputStream+IOUtils.copy,代码更简洁规范:
Files.copy(stream, filePath, StandardCopyOption.REPLACE_EXISTING);

内容的提问来源于stack exchange,提问作者sanjeevRm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 23:25:18