前端无法用正则校验压缩包内文件类型,因正则仅能匹配file.name或file.type,而二者均不反映zip/rar内部结构;真正有效的校验必须由后端流式解压并检查每个条目的真实mime和文件名。

前端无法用正则表达式校验压缩包内文件类型——pattern 和任何 JavaScript 正则都只能作用于 file.name 或 file.type,而这两者完全不反映 ZIP/RAR 内部内容。
为什么 pattern=".zip" 根本没用
浏览器的 accept 属性和 pattern 都只影响文件选择器界面或表单提交前的简单字符串匹配,它们对压缩包内部结构零感知:
-
accept=".zip":仅让文件对话框默认过滤后缀,用户点“所有文件”就能选payload.exe.zip或safe.jpg -
pattern="\.zip$":只能检查文件名是否以.zip结尾,但report.ZIP、data (1).zip、malware.zip.txt全部绕过 -
file.type === "application/zip":在部分安卓 WebView 中返回空字符串;即使命中,也只说明“这看起来像 ZIP”,不保证里面没shell.js或../etc/shadow
前端能做的唯一有效正则校验
仅限对 file.name 做大小写不敏感的后缀白名单过滤,并配合体积限制:
const file = input.files[0];
const ext = file.name.split('.').pop().toLowerCase();
if (!/^(zip|rar|7z|tar\.gz)$/.test(ext)) {
alert("仅支持 .zip、.rar、.7z、.tar.gz 格式");
input.value = ""; // 清空防止重复触发
return;
}
if (file.size > 50 * 1024 * 1024) { // 50MB
alert("文件不能超过 50MB");
return;
}
注意:/^(zip|rar|7z|tar\.gz)$/ 必须转义点号,且不能加 i 标志(pattern 属性不支持);实际使用中建议用 String.prototype.toLowerCase() 统一处理再比对。
JSZip 解压校验为何不可靠
试图在前端用 JSZip 读取内部文件名并正则匹配(如 /\.(jpg|png|pdf)$/i)会遇到真实阻碍:
- 大 ZIP(>100MB)加载卡死,主线程阻塞,iOS Safari 直接崩溃
- 加密 ZIP、ZIP64、含非 UTF-8 路径名的条目,
JSZip解析失败率超 40% - 仅靠文件名后缀判断类型极危险——
invoice.pdf.exe在 ZIP 里仍被当 PDF - 无法读取文件魔数(magic bytes),所以不能确认
photo.jpg真实 MIME 是image/jpeg还是text/html
真正起作用的校验必须落在后端
所有“压缩包里不能有 HTML/JS/EXE 文件”类需求,唯一可靠路径是:上传完整 ZIP → 后端流式解压 → 对每个条目做两层校验:
- 检查条目文件名后缀(白名单:.jpg、.pdf、.xlsx…)
- 读取条目前 12 字节,用
file-type(Node.js)或python-magic(Python)判断真实 MIME - 拒绝含路径穿越(
../../)、空文件名、超长路径的条目 - 重命名内部文件为哈希前缀(如
abc123_invoice.pdf),切断原始文件名信任链
前端所谓“提前提示压缩包含违规文件”,本质是向安全模型妥协;若 UI 强依赖,只能接受后端快速扫描(
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











