SonarQube提示归档文件处理存在安全风险:原因及修复方案
Zip文件列表读取的安全风险与修复
问题场景
我编写了如下Java方法:
public List<String> getZipFileList(String fullPath) throws IOException { logger.debug("====> ZipService: getZipFileList <===="); List<String> fileList = new ArrayList<>(); try (ZipFile zipFile = new ZipFile(fullPath)) { Enumeration<? extends ZipEntry> zipEntries = zipFile.entries(); while (zipEntries.hasMoreElements()) { String fileName = ((ZipEntry) zipEntries.nextElement()).getName(); fileList.add(fileName); } } return fileList; }
在Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();这一行,SonarQube给出提示:
请确保在此处解压该归档文件是安全的。
请问该操作存在哪些安全风险,以及如何进行修复?
存在的安全风险
- 路径遍历攻击:Zip条目的文件名可能包含
../、绝对路径(如/etc/passwd)等恶意内容。如果后续基于这个列表执行解压或文件操作,会导致程序访问/修改预期目录外的敏感文件,破坏系统安全性。 - Zip炸弹攻击:恶意Zip包可能包含海量极小文件,或者单个高度压缩的超大文件。即使当前方法仅读取文件名,若调用方后续基于此列表解压,会快速耗尽磁盘空间或内存,引发拒绝服务。
- 符号链接风险:Zip包中可能包含符号链接条目,后续操作若跟随该链接,可能访问到系统受保护的文件或目录,破坏系统完整性。
修复方案
1. 校验文件名,拦截路径遍历
对每个ZipEntry的文件名进行合法性校验,拒绝包含路径跳出字符或绝对路径的条目:
public List<String> getZipFileList(String fullPath) throws IOException { logger.debug("====> ZipService: getZipFileList <===="); List<String> fileList = new ArrayList<>(); try (ZipFile zipFile = new ZipFile(fullPath)) { Enumeration<? extends ZipEntry> zipEntries = zipFile.entries(); while (zipEntries.hasMoreElements()) { ZipEntry entry = zipEntries.nextElement(); String fileName = entry.getName(); // 拦截包含路径遍历字符、绝对路径的条目 if (fileName.contains("..") || fileName.startsWith("/") || fileName.startsWith("\\")) { throw new IOException("Invalid malicious file entry: " + fileName); } fileList.add(fileName); } } return fileList; }
2. 限制Zip包大小与条目数量
提前检查Zip文件大小,同时限制遍历的条目数量,防范Zip炸弹:
public List<String> getZipFileList(String fullPath) throws IOException { logger.debug("====> ZipService: getZipFileList <===="); List<String> fileList = new ArrayList<>(); File zipFile = new File(fullPath); // 限制Zip文件最大体积(示例:100MB) long maxAllowedSize = 100 * 1024 * 1024; if (zipFile.length() > maxAllowedSize) { throw new IOException("Zip file exceeds maximum allowed size"); } try (ZipFile zf = new ZipFile(zipFile)) { Enumeration<? extends ZipEntry> zipEntries = zf.entries(); int maxAllowedEntries = 1000; // 限制最大条目数 int entryCount = 0; while (zipEntries.hasMoreElements()) { if (entryCount++ >= maxAllowedEntries) { throw new IOException("Too many entries in zip file, potential zip bomb"); } ZipEntry entry = zipEntries.nextElement(); String fileName = entry.getName(); // 路径校验 if (fileName.contains("..") || fileName.startsWith("/") || fileName.startsWith("\\")) { throw new IOException("Invalid malicious file entry: " + fileName); } // 拦截符号链接 if (entry.isSymbolicLink()) { throw new IOException("Symbolic links are not permitted: " + fileName); } fileList.add(fileName); } } return fileList; }
3. 过滤符号链接条目
直接拒绝符号链接类型的ZipEntry,避免后续操作跟随链接访问敏感资源。
内容的提问来源于stack exchange,提问作者Rolf Warnecke
相关产品推荐
相关产品推荐

