解壓功能驗證正常,zip炸彈防御部分還沒驗證完,后續驗證后再確認
private static final int MAX_COUNT = 10000; // 注意,long類型后面要加L private static final long MAX_SIZE = 4L * 1024 * 1024 * 1024; private static final int PATH_LENGTH = 512; /** * zip解壓及zip炸彈的防御 * 防御要點:1.校驗解壓后文件大小 2.校驗解壓后的條目總數 3.解壓時防止跨目錄攻擊 * 4.校驗解壓文件路徑 5.校驗文件路徑長度 * @param zipFilePath */ public static void unzip(String zipFilePath) throws Exception { InputStream inputStream = null; FileOutputStream fileOutputStream = null; // 判斷是否zip文件 if (!isZipFile(zipFilePath)) { return; } // 創建解壓文件存放目錄 File file = new File("D:\\unzip"); if (!file.exists()) { file.mkdirs(); } // 使用ZipFile獲得解壓文件對象,第二個參數是編碼 ZipFile zipFile = new ZipFile(zipFilePath, Charset.forName("GBK")); // 用Enumeration接收壓縮文件中的每一個條目(目錄或文件) Enumeration<? extends ZipEntry> zipEntries = zipFile.entries(); // 統計條目數量 int count = 0; // 統計解壓文件大小 long size = 0L; // 遍歷zipEntries while (zipEntries.hasMoreElements()) { // 校驗zip解壓條目總數 if (++count > MAX_COUNT) { //TODO delete unzip files return; } // 獲得壓縮文件中此次的條目 ZipEntry zipEntry = zipEntries.nextElement(); size += zipEntry.getSize(); // 校驗解壓后的文件大小 if (size > MAX_SIZE) { // TODO delete unzip files return; } // 獲取此條目(文件或目錄)的路徑 String path = "D:\\unzip\\" + zipEntry.getName(); // 校驗文件路徑長度 if (path.length() > PATH_LENGTH) { // TODO delete unzip file return; } // 判斷解壓文件路徑是否合法 if (!isLegalPath(path)) { // TODO delete unzip files return; } // 是目錄則創建文件夾,是文件則用流讀寫出來 LOG.info("判斷是文件夾還是文件"); if (zipEntry.isDirectory()) { LOG.info("是文件夾"); new File(path).mkdirs(); } else { try { LOG.info("開始用流讀寫文件"); inputStream = zipFile.getInputStream(zipEntry); fileOutputStream = new FileOutputStream(path); byte[] data = new byte[8 * 1024]; int num = -1; while ((num = inputStream.read(data)) != -1) { fileOutputStream.write(data, 0, num); } } finally { if (fileOutputStream != null) { fileOutputStream.close(); } if (inputStream != null) { inputStream.close(); } } } } } /** * 判斷是否是zip文件 * @param zipFilePath * @return */ private static boolean isZipFile(String zipFilePath) { if (zipFilePath == null) { return false; } File file = new File(zipFilePath); if (file.exists() && file.getName().endsWith("zip")) { return true; } return false; } /** * 判斷解壓文件路徑是否合法 * @param path * @return */ private static boolean isLegalPath(String path) throws Exception { if (path == null) { return false; } if (new File(path).getCanonicalPath().startsWith("D:\\unzip\\")) { return true; } return false; }
修正后刪除本句話