import javax.xml.transform.stream.StreamResult;\r
\r
import org.apache.poi.openxml4j.opc.internal.ZipHelper;\r
+import org.apache.poi.openxml4j.util.ZipSecureFile;\r
import org.apache.poi.util.IOUtils;\r
import org.w3c.dom.Document;\r
import org.xml.sax.InputSource;\r
private final DocumentBuilder documentBuilder;\r
\r
public OOXMLPrettyPrint() throws ParserConfigurationException {\r
+ // allow files with much lower inflation rate here as there is no risk of Zip Bomb attacks in this developer tool\r
+ ZipSecureFile.setMinInflateRatio(0.00001);\r
+ \r
documentBuilder = documentBuilderFactory.newDocumentBuilder();\r
}\r
\r
import java.io.InputStream;\r
import java.io.PushbackInputStream;\r
import java.lang.reflect.Field;\r
-import java.nio.charset.Charset;\r
import java.util.zip.InflaterInputStream;\r
import java.util.zip.ZipEntry;\r
import java.util.zip.ZipException;\r
/**\r
* Sets the ratio between de- and inflated bytes to detect zipbomb.\r
* It defaults to 1% (= 0.01d), i.e. when the compression is better than\r
- * 1% for any given read package part, the parsing will fail\r
+ * 1% for any given read package part, the parsing will fail indicating a \r
+ * Zip-Bomb.\r
*\r
* @param ratio the ratio between de- and inflated bytes to detect zipbomb\r
*/\r
public static void setMinInflateRatio(double ratio) {\r
MIN_INFLATE_RATIO = ratio;\r
}\r
+ \r
+ /**\r
+ * Returns the current minimum compression rate that is used.\r
+ * \r
+ * See setMinInflateRatio() for details.\r
+ *\r
+ * @return The min accepted compression-ratio. \r
+ */\r
+ public static double getMinInflateRatio() {\r
+ return MIN_INFLATE_RATIO;\r
+ }\r
\r
/**\r
* Sets the maximum file size of a single zip entry. It defaults to 4GB,\r
* i.e. the 32-bit zip format maximum.\r
+ * \r
+ * This can be used to limit memory consumption and protect against \r
+ * security vulnerabilities when documents are provided by users.\r
*\r
* @param maxEntrySize the max. file size of a single zip entry\r
*/\r
MAX_ENTRY_SIZE = maxEntrySize;\r
}\r
\r
+ /**\r
+ * Returns the current maximum allowed uncompressed file size.\r
+ * \r
+ * See setMaxEntrySize() for details.\r
+ *\r
+ * @return The max accepted uncompressed file size. \r
+ */\r
+ public static long getMaxEntrySize() {\r
+ return MAX_ENTRY_SIZE;\r
+ }\r
+\r
public ZipSecureFile(File file, int mode) throws IOException {\r
super(file, mode);\r
}\r
if (counter < MAX_ENTRY_SIZE) {\r
if (cis == null) return;\r
double ratio = (double)cis.counter/(double)counter;\r
- if (ratio > MIN_INFLATE_RATIO) return;\r
+ if (ratio >= MIN_INFLATE_RATIO) return;\r
}\r
- throw new IOException("Zip bomb detected! Exiting.");\r
+ throw new IOException("Zip bomb detected! The file would exceed certain limits which usually indicate that the file is used to inflate memory usage and thus could pose a security risk. "\r
+ + "You can adjust these limits via setMinInflateRatio() and setMaxEntrySize() if you need to work with files which exceed these limits. "\r
+ + "Counter: " + counter + ", cis.counter: " + (cis == null ? 0 : cis.counter) + ", ratio: " + (cis == null ? 0 : ((double)cis.counter)/counter)\r
+ + "Limits: MIN_INFLATE_RATIO: " + MIN_INFLATE_RATIO + ", MAX_ENTRY_SIZE: " + MAX_ENTRY_SIZE);\r
}\r
\r
public ZipEntry getNextEntry() throws IOException {\r
if(e instanceof InvocationTargetException) {
InvocationTargetException t = (InvocationTargetException)e;
IOException t2 = (IOException)t.getTargetException();
- if("Zip bomb detected! Exiting.".equals(t2.getMessage())) {
+ if(t2.getMessage().startsWith("Zip bomb detected!")) {
return;
}
}
- if ("Zip bomb detected! Exiting.".equals(e.getMessage())) {
+ if(e.getMessage().startsWith("Zip bomb detected!")) {
return;
}
throw new IllegalStateException("Expected to catch an Exception because of a detected Zip Bomb, but did not find the related error message in the exception", e);
}
}
+