You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.13 17:14:31