...
| Code Block | ||
|---|---|---|
| ||
static final int BUFFER = 512;
// ...
public final void unzip(String filename) throws java.io.IOException{
FileInputStream fis = new FileInputStream(filename);
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis));
ZipEntry entry;
try {
while ((entry = zis.getNextEntry()) != null) {
System.out.println("Extracting: " + entry);
int count;
byte data[] = new byte[BUFFER];
// Write the files to the disk
FileOutputStream fos = new FileOutputStream(entry.getName());
BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER);
while ((count = zis.read(data, 0, BUFFER)) != -1) {
dest.write(data, 0, count);
}
dest.flush();
dest.close();
zis.closeEntry();
}
} finally {
zis.close();
}
}
|
Compliant Solution
In this compliant solution, the code validates the name of each entry before extracting the entry. If the name is invalid, the entire extraction is aborted. However, a compliant solution could also skip only that entry and continue the extraction process, or it could even extract the entry to some safe location.
...
| Code Block | ||
|---|---|---|
| ||
static final int BUFFER = 512;
static final int TOOBIG = 0x6400000; // 100MB
// ...
private String validateFilename(String filename, String intendedDir) {
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 final void unzip(String filename) throws java.io.IOException{
FileInputStream fis = new FileInputStream(filename);
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis));
ZipEntry entry;
try {
while ((entry = zis.getNextEntry()) != null) {
System.out.println("Extracting: " + entry);
int count;
byte data[] = new byte[BUFFER]; // Write the files to the disk, but ensure that the file is not insanely big
int total = 0;
String name = validateFilename(entry.getName(), ".");
FileOutputStream fos = new FileOutputStream(name);
BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER);
while (total <= TOOBIG && (count = zis.read(data, 0, BUFFER)) != -1) {
dest.write(data, 0, count);
total += count;
}
dest.flush();
dest.close();
zis.closeEntry();
if (total > TOOBIG) {
throw new IllegalStateException("File being unzipped is huge.");
}
}
} finally {
zis.close();
}
}
|
...