当Python遇到zip解压炸弹,防护不到位让你泪流满面!

zip解压炸弹

在文章的开头,让我们先来介绍一下zip解压炸弹是个什么妖怪

解压炸弹是指解压缩后能够产生巨大的数据量的可疑压缩文件!默认设置是文件扫描中产生500MB以上解压数据的是“解压炸弹”,实时监控中是100MB,邮件监控是30MB。
这样的压缩文件解压缩可能对解压程序造成严重负担或崩溃(可能用来攻击压缩软件以及占用大量电脑资源,或者杀毒软件的解压缩功能)。
解压炸弹内,还可能存在病毒,解压中会自启动窃取用户信息

如何制作解压炸弹

** 42.zip **是很有名的zip炸弹。一个42KB的文件,解压完其实是个4.5PB的“炸弹”。zip炸弹文件中有大量刻意重复的数据,这种重复数据在压缩的时候是可以被丢弃的,这也就是压缩后的文件其实并不大的原因。


42.zip

这一百多万个最终文件,每个大小为 4.3 GB 。
因此整个解压过程结束以后,会得到 1048576 * 4.6 GB = 4508876.8 GB
也就是 4508876.8 ÷ 1024 ÷ 1024 = 4.5 PB
这需要特殊的压缩算法和工具,但我们可以通过Python做一个简单的zip解压炸弹:

# -*- coding: utf-8 -*-
# @微信号   : King_Uranus
# @公众号    : 清风Python
# @GitHub   : https://github.com/BreezePython
# @Date     : 2020/09/08 23:30:33
# @File     : zip_boom.py
import os

def make_boom(file_path, file_num, string_len):
    if not os.path.exists(file_path):
        os.mkdir(file_path)
    os.chdir(file_path)
    for i in range(file_num):
        with open('boom%d.txt' % i, 'w',encoding='utf-8') as f:
            f.write('Boom' * string_len)

make_boom('zip_boom', 1000, 1000 * 1000)

我们快速创建1000个boom文件,每个文件中写入了一百万个boom,制作出了一个3.72GB的文件夹,然后只用7z工具的极限压缩效果,最终得到的zip文件只有4.8MB。


7z极限压缩

压缩效果
开始捣乱

我们自己制作的zip解压炸弹准备完毕,现在我们要找地方去黑别人的服务器了。找谁呢?刚好最近报了一个网易云课堂的Java微专业,他们每次提交打压的时候都是上传zip文件,然后老师获取到文件后解压进行批改,如图:


开始上传

上传成功

现在只要我提交附件,就可以静等批改作业的老师,把我按在地上摩擦了。(当然我肯定不会提交的...)这么大的一个网站,居然都没有对zip解压炸弹进行上传检查,可见大家日常开发过程中,存在多么大的安全隐患啊!

常规校验

正如刚才拿网易云课堂进行的上传演示,日常开发中我们对压缩文件的校验,主要分为类型、大小的校验。
比如我们Flask开发时,会通过flask_wtf校验文件类型:

from flask_wtf.file import FileField, \
    FileRequired, FileAllowed
allow_type = ['zip', 'rar', '7z']

class UploadForm(FlaskForm):
    zip_file = FileField('请上传文件:',
                         validators=[FileRequired(),
                         FileAllowed(allow_type)])
    submit = SubmitField()

同样的,会通过设置Flask最大文本长度对上传文件的大小进行校验

from flask import Flask
app = Flask(__name__)
app.config['SECRET_KEY'] = 'Breeze Python'
app.config['UPLOAD_PATH'] = os.path.join(app.root_path, 'uploads')
app.config['MAX_CONTENT_LENGTH'] = 30 * 1024 * 1024  # 30Mb

或者在文件读写过程中,通过os.path.getsize(filePath)来校验文件大小。
但如果你只做了如上方式,那么恭喜你一大波zip解压炸弹正向你赶来...

正确的方式

那么,我们可以通过什么方式来对zip解压炸弹进行预防呢?其实很简单:

  1. 文件数量
  2. 动态解析文件总大小

先上代码看看:

# -*- coding: utf-8 -*-
# @微信号   : King_Uranus
# @公众号    : 清风Python
# @GitHub   : https://github.com/BreezePython
# @Date     : 2020/09/08 23:30:33
# @File     : zip_boom.py
import zipfile
import os

def unzip(filename: str):
    # 限制最大文件数100
    max_file_num = 100
    # 设置解压内容最大值(一般平均最大的压缩率20,再高就很可能是异常文件了!)
    max_file_size = 1024 * 1024 * 100 * 20
    total_size = 0
    to_zip_file = zipfile.ZipFile(filename)
    dirname = filename.replace('.zip', '')
    # 校验文件总数量
    if len(to_zip_file.filelist) > max_file_num:
        raise ValueError("压缩文件的数量超过了上限")
    # 校验解压文件内容最大值
    for file in to_zip_file.filelist:
        total_size += file.file_size
        if total_size > max_file_size:
            raise IOError("压缩包内容异常")
    # 判断文件夹重复则退出
    if os.path.exists(dirname):
        print(f'{dirname} dir has already existed')
        return -1
    else:
        # 创建文件夹,并解压
        os.mkdir(dirname)
        to_zip_file.extractall(dirname)
        to_zip_file.close()

unzip('zip_boom.zip')

比如刚才的网易云课堂,学生做的解题答案,一个类加几个依赖文件了不起了。所以我们通过设置压缩包最大解压文件数进行检测。
我们再设置原始文件的最大内存上限(一般平均最大的压缩率不会超过20,再高就很可能是异常文件了!),起到二次校验的作用,最终达到zip解压炸弹的安全防护。
日常开发过程中,软件的安全、可信要时刻放在首要位置。不然你今天偷的懒,就是你明天流的泪啊!

The End

期待你关注我的公众号清风Python,如果你觉得不错,希望能动动手指转发给你身边的朋友们。
我的github地址:https://github.com/BreezePython

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354