如何在Python中安全提取用户上传的ZIP文件(防范Zip炸弹等漏洞)
如何在Python中安全提取用户上传的ZIP文件(防范Zip炸弹等漏洞)
做用户上传ZIP的功能可太容易踩坑了,尤其是Zip炸弹、路径遍历这类恶意文件的攻击,我之前做类似功能时踩过不少坑,现在把靠谱的方案整理给你:
一、用标准库zipfile手动实现安全校验
如果你优先想用Python自带的标准库,那绝对不能直接用extractall()裸奔!得自己手动加上几层安全校验,具体要覆盖这几个关键项:
- 限制总解压体积:提前计算所有文件解压后的总大小,设置一个合理的上限(比如1GB),防止小压缩包解压出几十上百GB的垃圾数据占满磁盘。
- 检查压缩比:正常文件的压缩比不会夸张到离谱,比如超过100:1就值得警惕了(纯文本最多也就几十倍),压缩比过高大概率是Zip炸弹。
- 拦截路径遍历:绝对不能让解压后的文件跳出你指定的目标目录,比如文件名里带
../或者绝对路径的,直接拒绝。 - 禁止链接文件:ZIP里如果包含软链接、硬链接,很可能是用来指向系统敏感文件的,必须直接拦截。
给你一段我自己用过的示例代码:
import zipfile import os def safe_extract_zip(zip_path, target_dir, max_total_size=1024*1024*1024, max_compression_ratio=100): # 确保目标目录存在,不存在就创建 os.makedirs(target_dir, exist_ok=True) total_uncompressed = 0 with zipfile.ZipFile(zip_path, 'r') as zf: for file_info in zf.infolist(): # 检查是否是路径遍历攻击 if os.path.isabs(file_info.filename) or '..' in file_info.filename: raise ValueError("发现非法文件路径,拒绝解压") # 检查是否是软/硬链接(Unix系统下) if file_info.create_system == 3: attr = file_info.external_attr >> 28 if attr == 4: raise ValueError("ZIP文件包含软链接,拒绝解压") elif attr == 8: raise ValueError("ZIP文件包含硬链接,拒绝解压") # 检查单个文件的压缩比 if file_info.compress_size > 0: ratio = file_info.file_size / file_info.compress_size if ratio > max_compression_ratio: raise ValueError(f"文件压缩比过高({ratio:.2f}:1),疑似Zip炸弹") # 累计总解压大小,超过限制就拒绝 total_uncompressed += file_info.file_size if total_uncompressed > max_total_size: raise ValueError(f"总解压大小超过限制({max_total_size/1024/1024:.2f}MB)") # 确保解压路径完全在目标目录内 target_file_path = os.path.join(target_dir, file_info.filename) if not os.path.abspath(target_file_path).startswith(os.path.abspath(target_dir)): raise ValueError("文件路径超出允许范围,拒绝解压") # 安全提取单个文件 zf.extract(file_info, target_dir) print("ZIP文件已安全解压完成")
二、用第三方库简化安全处理
如果不想自己手动写一堆校验逻辑,用第三方库是更省心的选择,比如defusedzip,它已经内置了所有常见的安全防护,路径遍历、Zip炸弹、恶意链接文件这些都能自动处理,用法和标准库的zipfile几乎一样,学习成本极低:
from defusedzip import zipfile as secure_zipfile def safe_extract_with_defusedzip(zip_path, target_dir): with secure_zipfile.ZipFile(zip_path, 'r') as zf: # defusedzip会自动处理各类安全风险 # 也可以根据需求手动设置解压大小限制等参数 zf.extractall(target_dir)
三、额外的安全小Tips
除了上面的校验,还有几个小细节能进一步提升安全性:
- 别信任ZIP里的文件名,最好自己重新命名所有解压后的文件,比如用UUID或者自定义的命名规则,避免特殊字符(像/、\、:这类)带来的意外问题。
- 如果有条件,解压前给ZIP文件做个病毒扫描,防止里面藏着恶意脚本。
- 解压操作尽量放在隔离的临时目录里,处理完业务逻辑后及时清理临时文件,减少残留风险。
- 给解压操作设置超时时间,防止恶意构造的ZIP文件让程序长时间挂起,拖垮服务。
备注:内容来源于stack exchange,提问作者sevic
相关产品推荐
相关产品推荐

