
SonarQube 提示“Make sure that expanding this archive file is safe here”是因为直接使用 ZipFile 未校验条目路径与大小,可能触发 ZIP 炸弹攻击或路径遍历漏洞,导致任意文件覆盖或内存耗尽。
sonarqube 提示“make sure that expanding this archive file is safe here”是因为直接使用 `zipfile` 未校验条目路径与大小,可能触发 zip 炸弹攻击或路径遍历漏洞,导致任意文件覆盖或内存耗尽。
ZIP 文件解析存在两类典型安全风险:
-
路径遍历(Directory Traversal):恶意 ZIP 中的条目名包含
../,若后续解压到本地目录,可能覆盖系统关键文件(如/etc/passwd或应用配置); - ZIP 炸弹(ZIP Bomb):极小体积 ZIP 包含高度嵌套/重复压缩内容(如 42.zip),解压后膨胀至 TB 级,引发内存溢出、拒绝服务(DoS)。
虽然您的代码当前仅列出文件名(未解压),但 SonarQube 将 ZipFile 的构造和 entries() 调用统一视为“archive expansion”上下文,因其底层仍会读取中央目录并初始化所有条目——而恶意 ZIP 可在中央目录中伪造超长文件名、异常压缩大小或嵌套结构,造成解析阶段资源耗尽或逻辑绕过。
✅ 安全修复方案(推荐):
-
校验 ZIP 条目路径合法性:确保每个
ZipEntry.getName()不含..、不以/开头、不为绝对路径; - 限制单个条目名称长度与总条目数(防内存滥用);
- 显式关闭资源(您已用 try-with-resources,这点正确);
-
避免信任用户输入的
fullPath:应校验文件存在性、权限及扩展名(如仅允许.zip)。
以下是加固后的安全实现:
public List<string> getZipFileList(String fullPath) throws IOException {
logger.debug("====> ZipService: getZipFileList fileList = new ArrayList();
// 基础校验:非空、合法扩展名、文件存在且可读
if (fullPath == null || !fullPath.toLowerCase().endsWith(".zip")) {
throw new IllegalArgumentException("Invalid ZIP file path");
}
Path zipPath = Paths.get(fullPath);
if (!Files.isRegularFile(zipPath) || !Files.isReadable(zipPath)) {
throw new IllegalArgumentException("ZIP file not found or unreadable");
}
try (ZipFile zipFile = new ZipFile(fullPath)) {
Enumeration extends ZipEntry> entries = zipFile.entries();
int entryCount = 0;
while (entries.hasMoreElements()) {
if (++entryCount > 10_000) { // 防 ZIP 炸弹:限制最大条目数
throw new IOException("Too many entries in ZIP file (possible bomb)");
}
ZipEntry entry = entries.nextElement();
String name = entry.getName();
// 路径安全校验:禁止目录遍历 & 空/非法路径
if (name.contains("..") || name.startsWith("/") || name.isEmpty()
|| name.charAt(0) == '\' || name.indexOf(':') != -1) {
throw new IOException("Suspicious ZIP entry name: " + name);
}
// 可选:限制文件名长度(防超长字符串 OOM)
if (name.length() > 256) {
throw new IOException("ZIP entry name too long: " + name.length());
}
fileList.add(name);
}
}
return fileList;
}</string>
⚠️ 注意事项:
- 若后续需实际解压文件,务必对每个
ZipEntry进行getRealPath()校验(使用Paths.get(baseDir, entry.getName()).normalize()并确认其仍在目标目录内); - 不要依赖
ZipEntry.getSize()或getCompressedSize()做安全判断——这些值可被恶意篡改; - 生产环境建议结合
ZipInputStream+ CRC 校验 + 流式限速,进一步防御流式 ZIP 炸弹; - SonarQube 规则
java:S2070(Unsafe ZIP archive extraction)默认启用,上述修复可彻底消除该告警。
总结:安全处理 ZIP 的核心是「零信任」——对每个条目名、数量、长度、层级均做白名单式校验,而非仅依赖 ZIP 解析库的默认行为。










