注册

压缩炸弹,Java怎么防止

一、什么是压缩炸弹,会有什么危害


1.1 什么是压缩炸弹


压缩炸弹(ZIP):一个压缩包只有几十KB,但是解压缩后有几十GB,甚至可以去到几百TB,直接撑爆硬盘,或者是在解压过程中CPU飙到100%造成服务器宕机。虽然系统功能没有自动解压,但是假如开发人员在不细心观察的情况下进行一键解压(不看压缩包里面的文件大小),可导致压缩炸弹爆炸。又或者压缩炸弹藏在比较深的目录下,不经意的解压缩,也可导致压缩炸弹爆炸。


以下是安全测试几种经典的压缩炸弹


graph LR
A(安全测试的经典压缩炸弹)
B(zip文件42KB)
C(zip文件10MB)
D(zip文件46MB)
E(解压后5.5G)
F(解压后281TB)
G(解压后4.5PB)

A ---> B --解压--> E
A ---> C --解压--> F
A ---> D --解压--> G

style B fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px
style C fill:#FFA07A,stroke:#FFA07A,stroke-width:2px
style D fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px
style E fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px
style F fill:#FFA07A,stroke:#FFA07A,stroke-width:2px
style G fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px


压缩炸弹(也称为压缩文件炸弹、炸弹文件)是一种特殊的文件,它在解压缩时会迅速膨胀成极其庞大的文件,可能导致系统资源耗尽、崩溃或磁盘空间耗尽。


压缩炸弹的原理是利用文件压缩算法中的重复模式和递归压缩的特性。它通常是一个非常小的压缩文件,但在解压缩时会生成大量的重复数据,导致文件大小迅速增长。这种文件的设计意图是迫使系统进行大量的解压缩操作,以消耗系统资源或填满磁盘空间。


压缩炸弹可能对系统造成严重的影响,包括系统崩溃、资源耗尽、拒绝服务攻击等。因此,它被视为一种恶意的计算机攻击工具,常常被用于恶意目的或作为安全测试中的一种工具。



1.2 压缩炸弹会有什么危害


graph LR
A(压缩炸弹的危害)
B(资源耗尽)
C(磁盘空间耗尽)
D(系统崩溃)
E(拒绝服务攻击)
F(数据丢失)

A ---> B
A ---> C
A ---> D
A ---> E
A ---> F

style B fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px
style C fill:#FFA07A,stroke:#FFA07A,stroke-width:2px
style D fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px
style E fill:#98FB98,stroke:#98FB98,stroke-width:2px
style F fill:#00FFFF,stroke:#00FFFF,stroke-width:2px

压缩炸弹可能对计算机系统造成以下具体的破坏:



  1. 资源耗尽:压缩炸弹在解压缩时会生成大量的重复数据,导致系统的CPU、内存和磁盘资源被迅速占用。这可能导致系统反应迟缓、无法响应用户的请求,甚至系统崩溃。
  2. 磁盘空间耗尽:由于压缩炸弹的膨胀特性,它可能在解压缩过程中填满磁盘空间。这会导致系统无法写入新的数据,造成磁盘空间耗尽,影响系统的正常运行。
  3. 系统崩溃:当一个压缩炸弹被解压缩时,系统可能由于资源耗尽或磁盘空间耗尽而崩溃。这可能导致系统重启或需要进行紧急修复,造成数据丢失或系统不可用的情况。
  4. 拒绝服务攻击:大规模的解压缩操作可能消耗大量系统资源,导致系统无法正常提供服务。这被恶意攻击者利用,用于进行拒绝服务攻击,使目标系统无法响应合法用户的请求。
  5. 数据丢失:在某些情况下,压缩炸弹可能会导致系统文件或数据的损坏或丢失。这可能发生在磁盘空间被耗尽时,写入操作无法成功完成的情况下。


重要提示:压缩炸弹可能对计算机系统造成不可逆的损害,请不要尝试创建、传播或使用压缩炸弹,以保护计算机和网络的安全。



二、怎么检测和处理压缩炸弹,Java怎么防止压缩炸弹


2.1 个人有没有方法可以检测压缩炸弹?


有一些方法可以识别和处理潜在的压缩炸弹,以防止对系统造成破坏。以下是一些常见的方法:


graph LR
A(个人检测压缩炸弹)
B(安全软件和防病毒工具)
C(文件大小限制)
D(文件类型过滤)

A ---> B --> E(推荐)
A ---> C --> F(太大的放个心眼)
A ---> D --> G(注意不认识的文件类型)

style B fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px
style C fill:#FFA07A,stroke:#FFA07A,stroke-width:2px
style D fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px
style E fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px
style F fill:#FFA07A,stroke:#FFA07A,stroke-width:2px
style G fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px


  1. 安全软件和防病毒工具(推荐):使用最新的安全软件和防病毒工具可以帮助检测和阻止已知的压缩炸弹。这些工具通常具备压缩文件扫描功能,可以检查文件是否包含恶意的压缩炸弹。
  2. 文件大小限制:设置对文件大小的限制可以帮助防止解压缩过程中出现过大的文件。通过限制解压缩操作的最大文件大小,可以减少对系统资源和磁盘空间的过度消耗。
  3. 文件类型过滤:识别和过滤已知的压缩炸弹文件类型可以帮助阻止这些文件的传输和存储。通过检查文件扩展名或文件头信息,可以识别潜在的压缩炸弹,并阻止其传输或处理。

2.2 Java怎么防止压缩炸弹


在java中实际防止压缩炸弹的方法挺多的,可以采取以下措施来防止压缩炸弹:


graph LR
A(Java防止压缩炸弹)
B(解压缩算法的限制)
C(设置解压缩操作的资源限制)
D(使用安全的解压缩库)
E(文件类型验证和过滤)
F(异步解压缩操作)
G(安全策略和权限控制)

A ---> B
A ---> C
A ---> D
A ---> E
A ---> F
A ---> G

style B fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px
style C fill:#FFA07A,stroke:#FFA07A,stroke-width:2px
style D fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px
style E fill:#98FB98,stroke:#98FB98,stroke-width:2px
style F fill:#ADD8E6,stroke:#ADD8E6,stroke-width:2px
style G fill:#00FFFF,stroke:#00FFFF,stroke-width:2px


  1. 解压缩算法的限制:限制解压缩算法的递归层数和重复模式的检测可以帮助防止解压缩过程无限膨胀。通过限制递归的深度和检测重复模式,可以及时中断解压缩操作并避免过度消耗资源。
  2. 设置解压缩操作的资源限制:使用Java的java.util.zipjava.util.jar等类进行解压缩时,可以设置解压缩操作的资源限制,例如限制解压缩的最大文件大小、最大递归深度等。通过限制资源的使用,可以减少对系统资源的过度消耗。
  3. 使用安全的解压缩库:确保使用的解压缩库是经过安全验证的,以避免存在已知的压缩炸弹漏洞。使用官方或经过广泛验证的库可以减少受到压缩炸弹攻击的风险。
  4. 文件类型验证和过滤:在解压缩之前,可以对文件进行类型验证和过滤,排除潜在的压缩炸弹文件。通过验证文件的类型、扩展名和文件头信息,可以识别并排除不安全的压缩文件。
  5. 异步解压缩操作:将解压缩操作放在异步线程中进行,以防止阻塞主线程和耗尽系统资源。这样可以保持应用程序的响应性,并减少对系统的影响。
  6. 安全策略和权限控制:实施严格的安全策略和权限控制,限制用户对系统资源和文件的访问和操作。确保只有受信任的用户或应用程序能够进行解压缩操作,以减少恶意使用压缩炸弹的可能性。

2.2.1 使用解压算法的限制来实现防止压缩炸弹


在前面我们说了Java防止压缩炸弹的一些策略,下面我将代码实现通过解压缩算法的限制来实现防止压缩炸弹。


先来看看我们实现的思路


graph TD
A(开始) --> B[创建 ZipFile 对象]
B --> C[打开要解压缩的 ZIP 文件]
C --> D[初始化 zipFileSize 变量为 0]
D --> E{是否有更多的条目}
E -- 是 --> F[获取 ZIP 文件的下一个条目]
F --> G[获取当前条目的未压缩大小]
G --> H[将解压大小累加到 zipFileSize 变量]
H --> I{zipFileSize 是否超过指定的大小}
I -- 是 --> J[调用 deleteDir方法删除已解压的文件夹]
J --> K[抛出 IllegalArgumentException 异常]
K --> L(结束)
I -- 否 --> M(保存解压文件) --> E
E -- 否 --> L

style A fill:#00FFFF,stroke:#00FFFF,stroke-width:2px
style B fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px
style C fill:#FFA07A,stroke:#FFA07A,stroke-width:2px
style D fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px
style E fill:#98FB98,stroke:#98FB98,stroke-width:2px
style F fill:#ADD8E6,stroke:#ADD8E6,stroke-width:2px
style G fill:#00FFFF,stroke:#00FFFF,stroke-width:2px
style H fill:#E6E6FA,stroke:#E6E6FA,stroke-width:2px
style I fill:#ADD8E6,stroke:#ADD8E6,stroke-width:2px
style J fill:#00FFFF,stroke:#00FFFF,stroke-width:2px
style K fill:#E6E6FA,stroke:#E6E6FA,stroke-width:2px
style L fill:#FFA07A,stroke:#FFA07A,stroke-width:2px
style M fill:#ADD8E6,stroke:#ADD8E6,stroke-width:2px

实现流程说明如下:



  1. 首先,通过给定的 file 参数创建一个 ZipFile 对象,用于打开要解压缩的 ZIP 文件。
  2. zipFileSize 变量用于计算解压缩后的文件总大小。
  3. 使用 zipFile.entries() 方法获取 ZIP 文件中的所有条目,并通过 while 循环逐个处理每个条目。
  4. 对于每个条目,使用 entry.getSize() 获取条目的未压缩大小,并将其累加到 zipFileSize 变量中。
  5. 如果 zipFileSize 超过了给定的 size 参数,说明解压后的文件大小超过了限制,此时会调用 deleteDir() 方法删除已解压的文件夹,并抛出 IllegalArgumentException 异常,以防止压缩炸弹攻击。
  6. 创建一个 File 对象 unzipped,表示解压后的文件或目录在输出文件夹中的路径。
  7. 如果当前条目是一个目录,且 unzipped 不存在,则创建该目录。
  8. 如果当前条目不是一个目录,确保 unzipped 的父文件夹存在。
  9. 创建一个 FileOutputStream 对象 fos,用于将解压后的数据写入到 unzipped 文件中。
  10. 通过 zipFile.getInputStream(entry) 获取当前条目的输入流。
  11. 创建一个缓冲区 buffer,并使用循环从输入流中读取数据,并将其写入到 fos 中,直到读取完整个条目的数据。
  12. 最后,在 finally 块中关闭 fos 和 zipFile 对象,确保资源的释放。

实现代码工具类


import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
* 文件炸弹工具类
*
* @author bamboo panda
* @version 1.0
* @date 2023/10
*/

public class FileBombUtil {

/**
* 限制文件大小 1M(限制单位:B)[1M=1024KB 1KB=1024B]
*/

public static final Long FILE_LIMIT_SIZE = 1024 * 1024 * 1L;

/**
* 文件超限提示
*/

public static final String FILE_LIMIT_SIZE_MSG = "The file size exceeds the limit";

/**
* 解压文件(带限制解压文件大小策略)
*
* @param file 压缩文件
* @param outputfolder 解压后的文件目录
* @param size 限制解压之后的文件大小(单位:B),示例 3M:1024 * 1024 * 3L (FileBombUtil.FILE_LIMIT_SIZE * 3)
* @throws Exception IllegalArgumentException 超限抛出的异常
* 注意:业务层必须抓取IllegalArgumentException异常,如果msg等于FILE_LIMIT_SIZE_MSG
* 要考虑后面的逻辑,比如告警
*/

public static void unzip(File file, File outputfolder, Long size) throws Exception {
ZipFile zipFile = new ZipFile(file);
FileOutputStream fos = null;
try {
Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();
long zipFileSize = 0L;
ZipEntry entry;
while (zipEntries.hasMoreElements()) {
// 获取 ZIP 文件的下一个条目
entry = zipEntries.nextElement();
// 将解缩大小累加到 zipFileSize 变量
zipFileSize += entry.getSize();
// 判断解压文件累计大小是否超过指定的大小
if (zipFileSize > size) {
deleteDir(outputfolder);
throw new IllegalArgumentException(FILE_LIMIT_SIZE_MSG);
}
File unzipped = new File(outputfolder, entry.getName());
if (entry.isDirectory() && !unzipped.exists()) {
unzipped.mkdirs();
continue;
} else if (!unzipped.getParentFile().exists()) {
unzipped.getParentFile().mkdirs();
}

fos = new FileOutputStream(unzipped);
InputStream in = zipFile.getInputStream(entry);

byte[] buffer = new byte[4096];
int count;
while ((count = in.read(buffer, 0, buffer.length)) != -1) {
fos.write(buffer, 0, count);
}
}
} finally {
if (null != fos) {
fos.close();
}
if (null != zipFile) {
zipFile.close();
}
}

}

/**
* 递归删除目录文件
*
* @param dir 目录
*/

private static boolean deleteDir(File dir) {
if (dir.isDirectory()) {
String[] children = dir.list();
//递归删除目录中的子目录下
for (int i = 0; i < children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
// 目录此时为空,可以删除
return dir.delete();
}

}

测试类


import java.io.File;

/**
* 文件炸弹测试类
*
* @author bamboo panda
* @version 1.0
* @date 2023/10
*/

public class Test {

public static void main(String[] args) {
File bomb = new File("D:\temp\3\zbsm.zip");
File tempFile = new File("D:\temp\3\4");
try {
FileBombUtil.unzip(bomb, tempFile, FileBombUtil.FILE_LIMIT_SIZE * 60);
} catch (IllegalArgumentException e) {
if (FileBombUtil.FILE_LIMIT_SIZE_MSG.equalsIgnoreCase(e.getMessage())) {
FileBombUtil.deleteDir(tempFile);
System.out.println("原始文件太大");
} else {
System.out.println("错误的压缩文件格式");
}
} catch (Exception e) {
e.printStackTrace();
}
}

}

三、总结


文件炸弹是一种恶意的计算机程序或文件,旨在利用压缩算法和递归结构来创建一个巨大且无限增长的文件或文件集
合。它的目的是消耗目标系统的资源,如磁盘空间、内存和处理能力,导致系统崩溃或无法正常运行。文件炸弹可能是有意制造的攻击工具,用于拒绝服务(DoS)攻击或滥用资源的目的。


文件炸弹带来的危害极大,作为开发人员,我们必须深刻认识到文件炸弹的危害性,并始终保持高度警惕,以防止这种潜在漏洞给恐怖分子以可乘之机。


总而言之,我们作为开发人员,要深刻认识到文件炸弹的危害性,严防死守,不给恐怖分子任何可乘之机。通过使用安全工具、限制文件大小、及时更新软件、定期备份数据以及加强安全意识,我们可以有效地防止文件炸弹和其他恶意活动对系统造成损害。


在中国,网络安全和计算机犯罪问题受到相关法律法规的管理和监管。以下是一些中国关于网络安全和计算机犯罪方面的法律文献,其中也涉及到文件炸弹的相关规定:




  1. 《中华人民共和国刑法》- 该法律规定了各种计算机犯罪行为的法律责任,包括非法控制计算机信息系统、破坏计算机信息系统功能、非法获取计算机信息系统数据等行为,这些行为可能涉及到使用文件炸弹进行攻击。
  2. 《中华人民共和国网络安全法》- 该法律是中国的基本法律,旨在保障网络安全和维护国家网络空间主权。它规定了网络安全的基本要求和责任,包括禁止制作、传播软件病毒、恶意程序和文件炸弹等危害网络安全的行为。
  3. 《中华人民共和国计算机信息系统安全保护条例》- 这是一项行政法规,详细规定了计算机信息系统安全的保护措施和管理要求。其中包含了对恶意程序、计算机病毒和文件炸弹等威胁的防范要求。


作者:独爱竹子的功夫熊猫
来源:juejin.cn/post/7289667869557178404

0 个评论

要回复文章请先登录注册