Check inputs to java.util.ZipInputStream
for cases that cause consumption of excessive system resources. Denial of service can occur when resource usage is disproportionately large in comparison to the input data that causes the resource usage.
This guideline is of greater concern for persistent, server-type systems than for desktop applications. Checking inputs for excessive resource consumption may be unjustified for client software that expects the user to handle resource-related problems. Even for client software, however, should check for inputs that could cause persistent denial of service, such as filling up the file system.
SCG 2009 lists some examples of possible attacks:
...
The nature of the Zip algorithm permits the existence of "zip bombs" whereby a short file is very highly compressed, for instance, ZIPs, GIFs and gzip encoded http contents.
...
The Zip algorithm is capable of producing very large compression ratios [Mahmoud 2002]. The example below shows a file that was compressed from 148MB to 590KB, a ratio of more than 200 to 1. The file consists of arbitrarily repeated data: alternating lines of 'a' characters and 'b' characters. Even higher compression ratios can be easily obtained using more input data, more targeted input data, and other compression methods.
Any entry in a Zip file whose uncompressed filesize is beyond a certain limit must not be uncompressed. The actual limit is dependent on the capabilities of the platform.
This guideline is a specific example of the more general guideline IDS18-J. Check for inputs that would cause excessive resource consumption
...
.
Noncompliant Code Example
...
Code Block | ||
---|---|---|
| ||
// external data source: args[0] const int BUFFER = 512; BufferedOutputStream dest = null; FileInputStream fis = new FileInputStream(args[0]); ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis)); ZipEntry entry; 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()); dest = new BufferedOutputStream(fos, BUFFER); while ((count = zis.read(data, 0, BUFFER)) != -1) { dest.write(data, 0, count); } dest.flush(); dest.close(); } zis.close(); |
Implementation Details
The Zip algorithm is capable of producing very large compression ratios [Mahmoud 2002]. The example below shows a file that was compressed from 148MB to 590KB, a ratio of more than 200 to 1. The file consists of arbitrarily repeated data: alternating lines of 'a' characters and 'b' characters. Even higher compression ratios can be easily obtained using more input data, more targeted input data, and other compression methods.
Compliant Solution
In this compliant solution, the code inside the while loop uses the ZipEntry.getSize()
to find the uncompressed filesize of each entry in a zip archive before extracting the entry. It throws an exception if the entry to be extracted is too large — 100MB in this case.
...
Guideline | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
IDS18 IDS21-J | low | probable | high | P2 | L3 |
Bibliography
...