关于本文
本文是通过利用生成式AI的自动化生成流程创建的。参考Python官方的zipfile文档,整理了在不解压ZIP的情况下确认文件名、大小以及加密标志的方法。验证状态:📘 参考官方规范确认后编写・所发布的实机运行代码未经实际验证
想查看通过邮件接收的ZIP文件的内容。但是,直接解压未知文件令人感到不安。在这种情况下,有一种方法可以在不解压的情况下读取目录(中心目录)信息。仅使用Python的标准库 zipfile 即可列出文件名、原始大小和压缩后的大小。
| 项目 | 条件 |
|---|---|
| 对象 | 希望安全预先调查ZIP内容的初学者和业务负责人 |
| 环境 | Python 3、要调查的ZIP的副本 |
| 额外安装 | 不需要 |
| 文件更改 | 仅读取ZIP。不进行解压或覆盖 |
| 限制 | 可以查看文件列表,但不保证其内容的安全性或真实性 |
首先尝试列出文件
将调查对象的副本放在工作文件夹中,命名为 sample.zip ,并将以下 Python 代码保存为 inspect_zip.py 。请注意不要将机密文件名发送到日志或外部服务。
from pathlib import Path
from zipfile import ZipFile, BadZipFile
archive = Path("sample.zip")
try:
with ZipFile(archive, "r") as zf:
for item in zf.infolist():
kind = "DIR" if item.is_dir() else "FILE"
encrypted = "yes" if item.flag_bits & 0x1 else "no"
print(
f"{kind}\t{item.file_size}\t"
f"{item.compress_size}\t{encrypted}\t{item.filename}"
)
except (BadZipFile, OSError) as error:
print(f"ZIPを読み取れません: {error}")
预计会从前往后依次显示:类型、解压后的字节数、压缩后的字节数、加密标志以及文件名。此输出是从规范中推导出的预期结果,而非执行日志。
infolist() 返回的 ZipInfo 包含各个条目的元数据。file_size 是解压后的大小,compress_size 是压缩后的大小。目录可以通过 is_dir() 来判断。
观察要点
| 观察结果 | 可能的含义 | 下一步应对措施 |
|---|---|---|
| 意外的文件名 | 发送方的解释与内容可能不符 | 不解压直接向发送方确认 |
| 解压后的大小异常庞大 | 解压时可能会消耗磁盘空间 | 确认容量和运维限制 |
| 加密标志为 yes | 可能是加密条目 | 通过正规共享途径确认 |
| 无法读取 ZIP | 损坏、格式不符、访问权限等 | 确认原始数据和文件格式 |
flag_bits & 0x1 仅检查 ZIP 通用用途标志中的加密位。它不评估加密方式或密码强度。 此外,仅获取列表并不等于进行了病毒扫描。
为什么不解压也能知道
ZIP 中除了文件内容之外,还有记录条目名称和大小的中央目录。ZipFile 读取该信息,infolist() 并返回列表。本次代码不会调用 extract() 或 extractall()。因此,不会将 ZIP 内的文件写入指定文件夹。
但这并不意味着 ZIP 解析本身完全无害。对于不受信任的输入,请使用已更新的 Python,并在可能的情况下于隔离环境中处理。
修改一处进行尝试
如果列表很长,for item in zf.infolist(): 的紧后面添加以下条件:
if item.is_dir():
continue
这样就可以得到排除了目录条目的文件列表。修改后的预期行为是根据规范推测的,未经运行验证。
失败时的故障排除
FileNotFoundError如果显示 :请检查 ZIP 名称和运行时的当前工作文件夹。在此示例中,它将被捕获为OSError。BadZipFile的情况:可能存在文件损坏或不是 ZIP 格式等原因。请勿仅凭扩展名判断是否为 ZIP。文件名出现乱码的情况:原因可能是 ZIP 创建工具的字符编码指定或兼容性问题。请不要修改原始 ZIP,而是与创建方进行确认。
列表为空的情况:ZIP 中可能没有任何条目。请勿凭空猜测其中是否存在内容。
注意:查看列表与安全解压是两码事
ZIP 的条目名称中可能包含相对路径或可疑名称。仅确认名称并不意味着可以安全地进行解压。特别是,使用文件名自行构建保存路径的处理需要做好路径遍历防护。请同时注意解压后总尺寸巨大的 ZIP,或是包含大量条目的 ZIP。
本次的方法是解压前的初步确认。它不能替代接收方的确认、恶意软件防范以及按需在隔离环境中进行的检查。
图解:读取 ZIP“目录”的机制
ZIP 并不只是单纯的压缩数据块。它有一个名为“中心目录”的目录,里面整理了各个条目的名称和大小等信息,Python 的 ZipFile 可以利用它来生成列表。将文件实际写出到外部的“解压”与引用 ZIP 中记录的信息的“显示列表”是不同的操作。
flowchart LR
A["ZIPアーカイブ"] --> B["圧縮された各ファイル"]
A --> C["中央ディレクトリ(目次)"]
C --> D["ZipInfoで名前・容量・フラグを読む"]
D --> E["一覧を表示"]
E --> F["想定外のファイルを探す"]
B -.->|"一覧表示では展開しない"| E
此图为概念图,并不严格表示 ZIP 内部的物理存储位置。即使能够读出目录中的名称,也不能保证该条目可以被正常取出或安全执行。如果是从外部接收的 ZIP,目录中的信息也应作为外部输入进行谨慎处理。
制作内容已知的练习用 ZIP
没有必要将未知的文件作为第一个教材。如果你自己制作一个只包含虚构 CSV 和简短说明文的 ZIP,就可以放心地将列表显示的各列与实际内容进行对比。以下代码是新建练习用文件的示例。当同名文件存在时,它会停止运行而不会覆盖。由于在撰写本文时未运行过,以下为预想步骤而非实测步骤。
from pathlib import Path
from zipfile import ZIP_DEFLATED, ZipFile
output = Path("training-archive.zip")
if output.exists():
raise FileExistsError("同名ファイルがあるため中断します")
with ZipFile(output, "w", compression=ZIP_DEFLATED) as zf:
zf.writestr("report/summary.csv", "項目,値\nA,1\n")
zf.writestr("readme.txt", "これは架空の教材です")
print("練習用ZIPを作成しました:", output)
如果在前半部分的列表代码中指定此 ZIP,预计会显示 report/summary.csv 和 readme.txt。由于 ZIP 内并不一定总是独立存在文件夹条目,因此“显示为 2 个文件,但也能看到文件夹”这种表面上的差异并不一定属于异常。此外,字符数和字节数也不一致。在比较包含日语的文本大小时,如果能意识到它在 UTF-8 下占用了多少字节,将有助于进一步理解。
压缩并不一定意味着体积一定会变小
重复内容较多的文章很容易被大幅压缩,而像 JPEG 图像或视频这样已经压缩过的数据,则往往很难变小。对于非常短的字符串,由于压缩所需的附加信息,压缩后反而可能会显得更大。因此,即使显示“压缩后大小大于原始大小”,也不能仅凭这一点判定为文件损坏或攻击。
那么,如果压缩后的大小相对于原始大小小得离谱,又该如何呢?虽然可能是指包含大量相同重复数据的文件,但也需要防范类似“ZIP 炸弹”这样会在解压时消耗大量内存和处理时间的风险。不过,我们既不能仅凭压缩率高这一单一数值来确认为恶意,也不能因为低就判断为安全。必须将文件数量、原始大小总和、格式以及接收目的结合起来综合评估。
解压前确认的顺序
flowchart TD
A["ZIPの一覧を取得"] --> B{"一覧が読めたか"}
B -->|"いいえ"| C["破損・形式・対応版を確認して保留"]
B -->|"はい"| D{"不審なパス・容量・件数があるか"}
D -->|"はい"| E["展開せず送付元と用途を確認"]
D -->|"いいえ"| F["暗号化・期待したファイル名を確認"]
F --> G{"内容を取り出す必要があるか"}
G -->|"ない"| H["一覧確認のみで終了"]
G -->|"ある"| I["別の安全な検査・展開工程へ"]
在这个流程中,并不能因为能够读取文件列表就认定为安全。例如,假设在工作中预期只接收一份 PDF 文件,但其中却包含了数十个可执行格式的文件扩展名,这就成为了决定不解压并向接收方进行确认的判断依据。反之,即使只排列着预期的 PDF 名称,也无法得知其内容的真伪或是否混入了恶意软件。
即使 ZIP 内部的名称中包含表示父目录的符号或绝对路径之类的表述,也不会仅通过列表显示就写入到该位置。但是,将该名称直接与保存路径关联的自主解压处理是危险的。路径遍历防护在解压过程中是必不可少的。有加密标志并不意味着安全。加密与否和内容是否可检测是两码事。
在共享文件列表时也要考虑隐私
即使不解压文件本身,内部的文件名有时也可能包含客户名称、案件编号或个人信息。如果直接将其粘贴到调查日志或聊天中,仅凭目录就可能会导致信息泄露。应当缩小共享范围,例如只标明所需的扩展名或数量。即使文件名出现乱码,也不要立即修改名称并重新保存原始 ZIP,而应确认创建工具及字符编码相关的条件。
如果在工作中应用,需将“初步检查”与“安全解压”分离开来
以每天收到的批处理文件为例进行思考。如果预设 ZIP 中包含固定的 CSV,则可以在收到后立即列出文件名、数量和原始大小,并设计将与预期大不相同的文件交由人工确认的流程。这并非检查“内容是否正确”的验证,而是在早期阶段确认“结构看起来是否符合预期”的检查。
在真正处理内容的阶段,则需要采取其他安全措施,例如病毒防护、发送方的可靠性、实际的数据验证以及保存位置的权限等。为了避免将成功获取文件列表与可用作业务数据混为一谈,如果在操作手册中明确规定判定范围,将更便于在实际业务中使用。“不打开就能查明的事情”与“不打开就无法明白的事情”的区分,正是这项微小技术的重要用途。
总结
不要直接解压 ZIP,ZipFile.infolist() 即可通过它检查内部的名称和容量。通过对比原始大小和压缩大小,如果发现非预期的文件或极端的容量,请在解压前停下来进行确认。这不是为了保证安全性,而是为了增加判断依据的小步骤。
官方资料
验证备忘录(2026年11月5日):基于官方文档构建。代码运行、实际 ZIP 验证以及 WordPress 显示确认暂未实施。
