Skip to content

Instantly share code, notes, and snippets.

@riversun
Last active August 24, 2016 09:46
Show Gist options
  • Save riversun/1ddd1b5251376731cf12 to your computer and use it in GitHub Desktop.
Save riversun/1ddd1b5251376731cf12 to your computer and use it in GitHub Desktop.
[Java]Class to extract the zip file using ZipInputStream in consideration of safety and security for Java
/**
* Copyright 2006-2016 Tom Misawa(riversun.org@gmail.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
* Unzipper for JAVA <br>
* <br>
* Coded according to IDS04-J/CERT manners
* @author Tom Misawa (riversun.org@gmail.com)
*/
public class Unzipper {
/**
* Edit here<br>
* Default is 100MB limit size of an entry file
*
*/
private static final int MAX_FILE_SIZE_BYTES = 100 * 1024 * 1024;
/**
* Edit here <br>
* Default is 1024 files limit of entry files
*
*/
private static final int MAX_ZIP_FILE_ENTRIES = 1024;
private static final int BUFFER_SIZE = 1024;
/**
* Unzip a zip file
*
* @param zipFile
* @param extractDir
*/
public final void unzip(File zipFile, final File extractDir) {
if (zipFile.isFile() == false) {
throw new RuntimeException("Specified zipFile is not a file.");
}
final File outDir = new File(extractDir.getAbsolutePath() + File.separator + getFileBodyName(zipFile));
if (outDir.exists() == false) {
boolean ourDirMakeSuccess = outDir.mkdirs();
if (ourDirMakeSuccess == false) {
throw new RuntimeException("outDir " + outDir.getAbsolutePath() + " make failure.");
}
}
// inputstreams
FileInputStream fis = null;
BufferedInputStream bis = null;
ZipInputStream zis = null;
ZipEntry entry = null;
int totalZipEntries = 0;
long totalBytesRead = 0;
try {
fis = new FileInputStream(zipFile);
bis = new BufferedInputStream(fis);
zis = new ZipInputStream(bis);
while ((entry = zis.getNextEntry()) != null) {
int count;
byte data[] = new byte[BUFFER_SIZE];
// Write the files to the disk, but ensure that the filename is
// valid, and that the file is not insanely big
String entryName = entry.getName();
validateFilename(entryName, ".");
// outputstreams in the loop
FileOutputStream fos = null;
BufferedOutputStream bos = null;
try {
File outFile = null;
if (entry.isDirectory()) {
outFile = new File(outDir, entryName);
outFile.mkdirs();
continue;
} else {
outFile = new File(outDir, entryName);
}
fos = new FileOutputStream(outFile);
bos = new BufferedOutputStream(fos, BUFFER_SIZE);
while (totalBytesRead + BUFFER_SIZE <= MAX_FILE_SIZE_BYTES && (count = zis.read(data, 0, BUFFER_SIZE)) != -1) {
bos.write(data, 0, count);
totalBytesRead += count;
}
bos.flush();
} finally {
//
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
zis.closeEntry();
totalZipEntries++;
if (totalZipEntries > MAX_ZIP_FILE_ENTRIES) {
throw new IllegalStateException("Too many files to unzip.");
}
if (totalBytesRead > MAX_FILE_SIZE_BYTES) {
throw new IllegalStateException("File being unzipped is too big.");
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (zis != null) {
try {
zis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void validateFilename(String filename, String intendedDir) throws java.io.IOException {
File f = new File(filename);
String canonicalPath = f.getCanonicalPath();
File iD = new File(intendedDir);
String canonicalID = iD.getCanonicalPath();
if (canonicalPath.startsWith(canonicalID)) {
// return canonicalPath;
} else {
throw new IllegalStateException("File is outside extraction target directory.");
}
}
public static String getFileBodyName(File file) {
String fileName = file.getName();
int lastIndexOfPeriod = fileName.lastIndexOf(".");
if (lastIndexOfPeriod > -1) {
return fileName.substring(0, lastIndexOfPeriod);
} else {
return fileName;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment