HTML5的accept属性仅作前端友好提示,无法真正限制文件类型;可靠校验需结合JavaScript读取文件头(magic number)与后端基于文件内容的双重验证。
HTML5 本身不能真正限制文件类型,accept 属性只是提示浏览器过滤文件选择器中的可选文件,用户仍可手动取消过滤、拖入任意文件,或通过开发者工具绕过。真正的类型校验必须在 JavaScript 中读取 File.type 或检查文件头(magic number),并在后端再次验证。
accept 属性做前端友好筛选它只影响文件选择对话框的默认过滤行为,不提供安全保证,但能提升用户体验:
accept="image/*":显示所有图片类型(image/jpeg、image/png 等)accept=".pdf,.docx":按扩展名匹配(注意开头的点不能省略)accept="application/pdf":按 MIME 类型匹配(依赖浏览器对文件头的识别能力)accept="image/png,image/jpeg,.svg"
有效,对拖放上传无直接影响File.type 和扩展名File.type 是浏览器根据文件头或扩展名推测出的 MIME 类型,不可靠(例如空文件、改后缀的文件会返回空字符串或错误类型),需配合扩展名二次判断:
绕过扩展名和 File.type 的欺骗,直接读取文件前几个字节判断真实类型。例如 PNG 文件头是 89 50 4E 47,JPEG 是 FF D8 FF:
FileReader.readAsArrayBuffer() 读取前 4 字节Uint8Array 解析字节序列示例片段(校验 JPEG):
const reader = new FileReader();
reader.onload = function(e) {
const buffer = e.target.result;
const view = new Uint8Array(buffer, 0, 3);
if (view[0] === 0xFF && view[1] === 0xD
8 && view[2] === 0xFF) {
console.log('确认是 JPEG');
}
};
reader.readAsArrayBuffer(file.slice(0, 3));
前端所有校验都可被跳过:accept 可被移除,JS 可被禁用或篡改,Content-Type 请求头可伪造。后端必须:
filename 和 Content-Type
python-magic、Node.js 的 file-type)读取文件头识别真实类型PIL、sharp),防止恶意构造的“图片”触发解析漏洞最常被忽略的一点:即使前端做了完整校验,只要没在服务端重做一遍,就等于没做。文件类型限制不是「前端做一次 + 后端做一次」,而是「后端必须做,前端只是辅助」。