前端校验文件头魔数是识别真实类型最可靠方式,需用Uint8Array读取二进制比对PNG、JPEG等特征,但仅为体验层防护,必须后端复核;应结合扩展名、MIME与魔数交叉验证,任一不匹配即拦截。

前端校验文件头魔数(Magic Number)是识别文件真实类型最可靠的方式之一,能有效防止用户通过篡改后缀(如把 evil.php 改成 evil.pdf)绕过类型检查。但要注意:这仍是**体验层防护**,必须配合后端魔数重检,否则毫无安全意义。
读取文件前几个字节判断真实格式
使用 FileReader 或更现代的 file.arrayBuffer() 读取文件开头若干字节,比对已知魔数特征:
- PNG:前 8 字节为
\x89PNG\r\n\x1a\n - JPEG:前 2 字节为
\xff\xd8 - PDF:前 4 字节为
%PDF(ASCII 字符) - ZIP(含 .docx/.xlsx/.jar):前 4 字节为
PK\x03\x04 - GIF:前 6 字节为
GIF87a或GIF89a
用 ArrayBuffer + Uint8Array 提取魔数
避免用字符串比较(编码易出错),直接操作二进制:
async function checkMagicNumber(file) {
const buffer = await file.arrayBuffer();
const view = new Uint8Array(buffer, 0, 8); // 读前 8 字节足够覆盖常见格式
if (view[0] === 0x89 && view[1] === 0x50 && view[2] === 0x4e && view[3] === 0x47) {
return 'png';
}
if (view[0] === 0xff && view[1] === 0xd8) {
return 'jpeg';
}
if (file.name.toLowerCase().endsWith('.pdf') &&
String.fromCharCode(...view.slice(0, 4)) === '%PDF') {
return 'pdf';
}
if (view[0] === 0x50 && view[1] === 0x4b && view[2] === 0x03 && view[3] === 0x04) {
return 'zip';
}
return null;
}
结合扩展名与 MIME 做交叉验证
单独依赖魔数或后缀都不够,三者联合可提升拦截准确率:
- 先提取
file.name.split('.').pop().toLowerCase()得到后缀 - 检查
file.type是否在白名单内(如image/png),但不信任它 - 调用魔数检测函数,确认结果与后缀/声明类型逻辑一致(例如后缀是
.png,魔数也匹配 PNG) - 任一不通过,清空 input 的
value并提示:“文件内容与后缀不符,请上传真实的 PNG 文件”
注意边界情况和性能
小文件(
- 不要用
FileReader.readAsText()处理二进制文件(会乱码) - 避免在主线程长时间阻塞:大文件校验建议用
Web Worker或AbortSignal控制超时 - 魔数只是基础门槛,不能替代后端的完整校验(如 ZIP 内嵌恶意文件、PDF 携带 JS 脚本等需深度解析)
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











