extractall() 默认直接覆盖同名文件且无提示;存在 Zip Slip 路径遍历漏洞,需手动校验路径;中文文件名可能因编码不匹配乱码;不支持密码解压,AES 加密需第三方库。

extractall() 会直接覆盖同名文件,没提示也没备份
默认情况下 extractall() 遇到目标路径已存在同名文件时,会直接覆盖,且不抛错、不警告。这在处理重要数据时非常危险——比如你解压一个旧备份包,结果把刚改完的配置文件冲掉了。
- 务必提前确认目标目录是否为空,或用
os.listdir()检查是否有冲突文件 - 更稳妥的做法是先用
zipfile.ZipFile.namelist()获取待解压文件列表,再逐个判断目标路径是否存在 - 如果需要保留原文件,可配合
shutil.move()或os.rename()在解压前重命名已有文件
路径遍历漏洞(Zip Slip)必须手动过滤
extractall() 不会自动阻止恶意压缩包里的 ../../etc/passwd 这类路径。Python 3.12+ 虽增加了 strict_zip_path 参数(默认 False),但老版本完全不校验,一解压就可能写到任意系统位置。
- 解压前必须对每个成员路径做规范化和白名单检查:用
os.path.normpath()归一化,再用os.path.commonpath([target_dir, abs_path]) != target_dir判断是否越界 - 简单粗暴但有效的方式:拒绝任何含
".."或以"/"开头的ZipInfo.filename - 别依赖
pwd或当前工作目录——extractall()的path参数才是唯一可信的根目录
中文文件名乱码?编码问题得自己兜底
Windows 打包的 zip 常用 GBK 编码存文件名,而 Python 的 zipfile 默认按 UTF-8 解码,导致 namelist() 返回一堆 .txt。这不是 extractall() 的 bug,是 ZIP 标准本身没强制编码规范。
- 先尝试用
zipfile.ZipFile.open(name, pwd=None)读取内容验证:如果内容正常,说明只是文件名编码错了 - 手动修复:用
zipfile.ZipFile.filelist遍历ZipInfo对象,对.filename字段用.encode('cp437').decode('gbk')(Windows 常见)或.encode('utf-8').decode('gbk')尝试转换 - Python 3.11+ 可传
metadata_encoding='gbk'给ZipFile构造函数,但仅限部分场景生效,不能全信
extractall() 不支持密码保护的 zip 文件
哪怕你传了 pwd=b'123',extractall() 也直接忽略——它底层调用的是无密码解压逻辑。遇到加密 zip,会报 RuntimeError: File "xxx" is encrypted, password required for extraction。
- 必须改用
ZipFile.extract()或ZipFile.open()逐个处理,且每次都要显式传pwd参数 - 注意:密码是 bytes 类型,不是字符串;空密码用
b'',不是None或"" - 如果 zip 是 AES 加密(而非传统 ZipCrypto),标准库完全不支持,得换
pyminizip或libarchive-c
实际解压逻辑里最麻烦的从来不是“怎么调用”,而是“怎么确保不炸掉生产环境”。路径校验、编码容错、密码兼容性,每个点都得单独补丁,没有银弹。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











