安全解压zip需三步路径校验:先filepath.clean归一化,再检查含“..”或以“/”开头,最后strings.hasprefix二次确认不越界;必须defer r.close()防泄露,每个file.open()后立即defer rc.close(),流式io.copy防oom,gbk中文名需golang.org/x/text/encoding/simplifiedchinese手动解码。

直接用 zip.OpenReader 打开 ZIP,再用 file.Open() 获取流读取目标文件内容,是安全、低内存、不落盘的标准做法——但必须校验路径、及时关闭句柄、处理中文名,否则轻则乱码、重则写穿系统目录。
怎么安全地打开并定位 ZIP 中的单个文件
ZIP 支持随机访问,zip.OpenReader 会解析中央目录区,不加载整个文件到内存。但别跳过完整性检查:
- 先用
os.Stat确认文件存在且Size() > 0 - 调用
r, err := zip.OpenReader("a.zip")后,立刻defer r.Close(),并检查r.Close()是否返回io.ErrUnexpectedEOF(说明 ZIP 截断) - 遍历
r.File查找目标文件时,别用strings.EqualFold粗暴匹配 —— 要用filepath.Clean(f.Name)归一化后再比对,否则./config/../etc/passwd会被放过
为什么 file.Open() 返回的 io.ReadCloser 必须立刻关
file.Open() 内部创建了 gzip.Reader(若启用 Deflate),不关会导致 zlib 解压器资源泄漏,几百个文件后触发 too many open files。常见错误是在循环里写 defer rc.Close(),结果所有句柄堆到函数末尾才释放。
在 Golang 中使用 samber/hot 进行内存缓存,支持 LRU、LFU、TinyLFU、W‑TinyLFU、S3FIFO、ARC、TwoQueue、SIEVE、FIFO 等淘汰算法,提供 TTL、缓存加载器及分片功能。
- 每个
file.Open()后必须紧跟defer rc.Close(),只作用于当前条目 - 别在
for _, f := range r.File循环体里 defer,应写成:rc, err := f.Open(); if err != nil { ... }; defer rc.Close() - 大文件别用
io.ReadAll(rc)—— 改用io.Copy(dst, rc)或bufio.NewScanner(rc)流式处理,避免 OOM
Windows 打的 ZIP 中文文件名怎么正确读出来
Go 的 archive/zip 默认按 UTF-8 解析 f.Name,但 Windows 资源管理器打的 ZIP 多用 GBK 编码,导致 f.Name 是一堆 ???.txt。这不是 Go 的 bug,是编码不一致。
-
header.SetUTF8(true)只在 Go 1.22+ 有效,且依赖 ZIP 包自己设置了 flags bit 1 —— 很多旧包没设,不可靠 - 优先让上游改用 UTF-8 打包:7-Zip 勾选 “UTF-8”,macOS / Linux
zip -U默认支持 - 必须兼容旧包时,用
golang.org/x/text/encoding/simplifiedchinese:decoded, _ := gbk.NewDecoder().String(f.Name)
提取前必须做的路径穿越防护
archive/zip 对 f.Name 完全放行,filepath.Join(dest, f.Name) 遇到 ../../../etc/passwd 就真往根目录写。防护不能只靠 strings.HasPrefix(f.Name, ".."),要分三步:
- 第一步:
cleanName := filepath.Clean(f.Name),把./a/../b变成b,把../x变成../x - 第二步:检查
cleanName是否仍含"..",或是否以"/"开头(Linux/macOS),Windows 下还要统一转小写、把"\"替换为"/" - 第三步:构造完整路径
dstPath := filepath.Join(absDest, cleanName),再用strings.HasPrefix(filepath.ToSlash(dstPath), filepath.ToSlash(absDest))二次确认没逃出根目录
漏掉任何一步,都可能被 Zip Slip 攻击利用。路径校验不是可选项,是上线前必须跑通的检查点。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










