每天都在解压,但加密强度一塌糊涂、中文文件名乱码、格式选错了导致同事打不开——是 ZIP 用户三大常见翻车。理解归档格式背后的设计权衡能避开这些坑。
ZIP 加密的两套体系
ZIP 文件可以加密,但”加密”两个字下面藏着完全不同的东西:
| 加密方式 | 出现年代 | 强度 | 兼容性 |
|---|---|---|---|
| ZipCrypto | 1989 | 形同虚设(已知明文攻击秒破) | 所有 ZIP 工具都支持 |
| AES-128 | 2003(WinZip 9) | 强 | 大多数现代工具 |
| AES-256 | 2003(WinZip 9) | 强 | 大多数现代工具,部分老旧工具不识别 |
关键事实:
- Windows 资源管理器自带的”压缩到 zip 文件 → 加密”用 ZipCrypto——给压缩包设置密码,但加密强度等于零
- 如果攻击者拿到这个 ZIP 里任何一个文件的明文片段(哪怕只有 12 字节),可以在几秒内推出密钥
- 即使没有明文,弱密钥的暴力破解也比 AES 快几个数量级
- 用 advzip / pkcrack 等开源工具可以验证
判断 ZIP 加密类型的方法:
# 7-zip 命令行
7z l -slt encrypted.zip | grep -i method
# 输出 "ZipCrypto" 还是 "AES-256"
# unzip 信息
unzip -lv encrypted.zip
# 加密标志列会显示
GUI 工具:用 7-Zip GUI 打开 ZIP,“方法”列直接告诉你。
实操建议:所有需要密码的归档只用 7z 或 AES-256 ZIP——避开 Windows 自带的”加密”。
中文文件名乱码的历史包袱
ZIP 规范早年没规定文件名编码——各系统按本地编码写。中文 Windows 用 GBK / CP936,Mac / Linux / 现代系统用 UTF-8。两边互传就乱码:
| 创建端 | 解压端 | 结果 |
|---|---|---|
| Windows 7-Zip(默认) | Mac / Linux | 乱码(“鏂囨。.txt”) |
| Windows 7-Zip(勾 UTF-8) | Mac / Linux | 正常 |
| Mac / Linux | Windows 资源管理器 | 乱码(“文档.txt”) |
| Mac / Linux | Windows 7-Zip | 乱码 |
ZIP 头部有一个 bit(General Purpose Bit Flag 第 11 位)标记”文件名是 UTF-8”。新版工具会读这个 bit 决定怎么解码:
- 设了 → 按 UTF-8 解
- 没设 → 按系统默认编码解(这就是乱码源头)
Windows 7-Zip 默认不打这个 bit——为了兼容老软件。要打开需要在选项里勾 “cu = on”(命令行 -mcu=on)。
修复方法:
# Linux / Mac 解压 GBK 中文 ZIP
unzip -O cp936 chinese.zip
# 7-Zip Mac 版(指定字符集)
# 在 GUI 设置里改"代码页"为 936
# 用 The Unarchiver(Mac)打开会自动识别
本工具基于 libarchive,对常见中文 ZIP 会做编码探测——但仍建议创建端用 UTF-8 标志位,从源头避免。
格式选型矩阵
| 格式 | 压缩比 | 速度 | 跨平台 | 加密 | 适用 |
|---|---|---|---|---|---|
| ZIP(Deflate) | 中 | 快 | 顶级 | AES-256 / ZipCrypto | Windows 用户分享、跨平台传输 |
| ZIP(Deflate64) | 中+ | 中 | 一般 | 同上 | 老 WinZip,避免使用 |
| 7z(LZMA2) | 最高 | 慢 5-10× | 需装 7-Zip | AES-256-CBC + 文件名 | 自己存档、网盘备份 |
| RAR | 高 | 中 | 差(需 WinRAR / unrar) | AES-256 | 避免(商业格式) |
| tar.gz | 中 | 快 | Linux/Mac 原生 | 无(需配合 GPG) | 源码分发、Linux 部署 |
| tar.bz2 | 高 | 中 | Linux/Mac 原生 | 无 | 已被 xz 取代 |
| tar.xz | 高+ | 慢 | Linux/Mac 原生 | 无 | Linux 大文件归档 |
| tar.zst | 高 | 极快 | 需 zstd(新) | 无 | 现代高速归档(Facebook 提出) |
实战建议:
- 传给同事 / 客户 → ZIP(任何系统都能开)
- 网盘备份大量文件 → 7z(体积小一半)
- 代码 / 配置归档 → tar.gz(Linux 工具链友好)
- Mac → Mac 之间 → 直接 ZIP(macOS Finder 创建的就是 UTF-8 ZIP,无乱码)
- 要密码 → 7z 优先,ZIP+AES-256 次之
7z 实体压缩的取舍
7z 的”实体压缩”(Solid Compression)是它压得小的关键:
普通压缩(按文件独立):
file1.txt → 压缩 → 块1
file2.txt → 压缩 → 块2
file3.txt → 压缩 → 块3
实体压缩(合并成大流):
file1.txt + file2.txt + file3.txt → 拼成一个大文件 → 压缩 → 单块
收益:相似文件(如同一项目的多个 .js 源码)之间能跨文件去重,体积能再降 20-50%。
代价:
- 解压其中一个文件要先解压它前面的所有文件——单文件随机访问慢
- 实体块越大压缩比越高但访问越慢,7-Zip 默认块大小 2GB
- 损坏一个字节会导致后面所有文件丢失
适用 / 不适用:
| 场景 | 适用 |
|---|---|
| 一次打包,整包归档 | ✓ 推荐 |
| 频繁单独取文件 | ✗ 关闭实体压缩 |
| 网盘冷备 / 异地备份 | ✓ 推荐 |
| 软件分发 / 安装包 | ✗ 用户解压时只想要部分文件 |
tar 的”两步走”
tar.gz、tar.xz 这种”双扩展名”是 Linux 习惯:
原始文件 → tar 打包(不压缩)→ gzip 压缩 → .tar.gz
tar 只把多个文件拼成一个大流(保留权限、时间、符号链接、设备文件等),不做压缩。然后用 gzip / bzip2 / xz / zst 任选一个压缩工具。
设计动机:
- 职责单一:tar 管打包,gzip 管压缩,互不干扰
- 流式处理:可以
tar c | gzip | ssh remote 'tar x'流式传输 - 可换压缩:同样的 tar 文件可换 xz、zst 重新压缩
代价是 tar 不支持部分提取——要解压其中一个文件理论上要扫描整个流(实践中支持但慢)。
解压时的几个坑
1. 路径穿越(Zip Slip)
恶意 ZIP 里文件名写 ../../../../etc/passwd,解压时跳出目录覆盖系统文件。本工具基于 libarchive 自动剥离 ..,但老旧解压工具没防护——慎用未知来源的 ZIP。
2. ZIP 炸弹
42KB 的 ZIP 解压后是 4.5GB(递归压缩)。本工具会显示文件总大小预警,但自动解压脚本要做大小限制(CI 里常见)。
3. 长文件名截断
Windows 路径限制 260 字符,深嵌套的 npm 项目压缩包解压时常报”路径过长”。Win10+ 可在注册表打开 LongPathsEnabled,或用 7-Zip 直接解(它内部走 NT 长路径 API)。
4. 符号链接被实体化
tar 保留符号链接,但解压到 Windows 时会被实体化为副本——节省的空间会膨胀。
一句话总结
ZipCrypto 别用、Windows 创建 ZIP 勾 UTF-8、跨平台分享用 ZIP / 自己存档用 7z / Linux 部署用 tar.gz——三个习惯改完几乎不会再翻车。