本文的文字及圖片來源于網路,僅供學習、交流使用,不具有任何商業用途,著作權歸原作者所有,如有問題請及時聯系我們以作處理,
以下文章來源于清風Python ,作者王翔
zip解壓炸彈
在文章的開頭,讓我們先來介紹一下zip解壓炸彈是個什么妖怪!
解壓炸彈是指解壓縮后能夠產生巨大的資料量的可疑壓縮檔案!默認設定是檔案掃描中產生500MB以上解壓資料的是“解壓炸彈”,實時監控中是100MB,郵件監控是30MB,這樣的壓縮檔案解壓縮可能對解壓程式造成嚴重負擔或崩潰(可能用來攻擊壓縮軟體以及占用大量電腦資源,或者殺毒軟體的解壓縮功能),解壓炸彈內,還可能存在病毒,解壓中會自啟動竊取用戶資訊
PB有多大
MB,全稱baiMByte,計算機中的一種儲存du單位,含義zhi是“兆位元組”,dao
1MB可儲存1024×1024=1048576位元組(Byte),
位元組(Byte)是存盤容量基本單位,1位元組(1Byte)由8個二進制位組成,
位(bit)是計算機存盤資訊的最小單位,二進制的一個“0”或一個“1”叫一位,
通俗來講,1MB約等于一張網路通用圖片(非高清)的大小,
1GB=1024MB,約等于下載一部電影(非高清)的大小,
1TB=1024GB,約等于一個固態硬碟的容量大小,能存放一個不間斷的監控攝像頭錄像(200MB/個)長達半年左右,
1PB=1024TB,容量相當大,應用于大資料存盤設備,如服務器等,
如何制作解壓炸彈
42.zip 是很有名的zip炸彈,一個42KB的檔案,解壓完其實是個4.5PB的“炸彈”,zip炸彈檔案中有大量刻意重復的資料,這種重復資料在壓縮的時候是可以被丟棄的,這也就是壓縮后的檔案其實并不大的原因,
這一百多萬個最終檔案,每個大小為 4.3 GB ,因此整個解壓程序結束以后,會得到 1048576 * 4.6 GB = 4508876.8 GB 也就是 4508876.8 ÷ 1024 ÷ 1024 = 4.5 PB 這需要特殊的壓縮演算法和工具,但我們可以通過Python做一個簡單的zip解壓炸彈:
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,
開始搗亂
我們自己制作的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解壓炸彈進行預防呢?其實很簡單:
- 檔案數量
- 動態決議檔案總大小
先上代碼看看:
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')
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/5973.html
標籤:Python
上一篇:Day3:函式與函式式編程
