本文主要是介绍应用软件安全编程--02从 ZipInputStream 安全解压文件,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
对java.util.ZipInputStream 的输入进行检查可以防止消耗过多的系统资源。解压一个文件,比如 zip、gif或者 gzip编码的 HTTP 内容,可能会消耗过多的资源,并且在压缩率极高的情况下,可能会导 致 zip炸弹的出现。
对于从 ZipInputStream 安全解压文件的情况,示例1给出了不规范用法(Java 语言)示例。示例2 给出了规范用法(Java 语言)示例。
示例1:static final int BUFFER = 512;/1.public final void unzip(String filename) throws java.io.IOException{FileInputStreamfis = new FileInputStream(filename);ZipInputStreamzis = new ZiplnputStream(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 diskFileOutputStreamfos = new FileOutputStream(entry.getName());BufferedOutputStreamdest = 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();}
这个不规范的代码示例没有检查解压一个文件时所消耗的资源。它会允许操作持续进行直至完 成,或者直至本地资源耗尽为止。
示例2:static final int BUFFER = 512;static final int TOOBIG = 0x6400000;// Max size of unzipped data,100MBstatic final int TOOMANY = 1024; // Max number of files//..private String 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 lllegalStateException("File is outside extraction target directory.");public final void unzip(String filename) throws java.io.IOException {FileInputStreamfis = new FileInputStream(filename);ZipInputStreamzis = new ZiplnputStream(new BufferedInputStream(fis));ZipEntry entry;int entries = 0;long total = 0;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 filename is valid,// and that the file is not insanely bigString name = validateFilename(entry.getName(),".");if (entry.isDirectory()){System.out.println("Creating directory"+ name);new File(name),mkdir();continue;FileOutputStreamfos = new FileOutputStream(name);BufferedOutputStreamdest = new BufferedOutputStream(fos, BUFFER);while(total+ BUFFER <= TOOBIG &.&.(count = zis.read(data,0,BUFFER))!=- 1){dest.write(data,0,count);total += count;dest.flush();dest.close();zis.closeEntry();entries++;if (entries 〉TOOMANY){throw new lllegalStateException("Too many files to unzip.");if (total 〉TOOBIG){throw new IllegalStateException("File being unzipped is too big.");} finally {zis.close();
}
在这个规范的代码示例中,代码在提取条目之前验证每个条目的名称。如果名称无效,那么整个提 取就会被中止。 while 循环中的代码将判断 zip归档中每个条目的文件大小,同时提取条目。如果提取 的条目太大,在本例中为100 MB, 则会抛出异常。代码不要使用ZipEntry.getSize()方法,因为攻击者 可以伪造 ZIP 文档中未压缩的文件的大小。最后,代码还计算压缩包中文件条目的数量,如果超过 1024个条目,则抛出异常。
这篇关于应用软件安全编程--02从 ZipInputStream 安全解压文件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!