accept属性仅前端界面过滤,不校验文件真实类型;服务端必须通过文件头(magic bytes)校验MIME,不可信客户端任何信息。

accept 属性只过滤前端界面,不校验文件真实类型
浏览器的 accept 属性只是提示用户选什么类型的文件,并不能阻止用户绕过选择器(比如手动修改文件扩展名、拖入不匹配的文件),甚至某些浏览器会忽略该属性直接显示所有文件。它本质是 UI 层的辅助筛选,不是安全边界。
常见错误现象:设置了 accept="image/png",但用户仍能选中 malicious.exe 并成功提交——只要扩展名是 .png,浏览器就放行;真实 MIME 类型在服务端才可可靠判定。
- 使用场景:表单中提升用户体验,减少误选非目标格式文件
- 参数差异:
accept支持 MIME 类型(如application/pdf)、文件扩展名(如.pdf)、类型通配符(如image/*),但不同浏览器对通配符支持程度不一(Safari 对audio/*支持较弱) - 不要混用扩展名和 MIME:写成
accept=".jpg, image/jpeg"没问题,但accept="jpg, jpeg"无效(缺点号)
正确写法:用逗号分隔多个 MIME 或扩展名
必须用英文逗号分隔,空格会被视为类型的一部分导致失效。例如 accept="image/png, image/jpeg, .pdf" 是合法的;而 accept="image/png , image/jpeg" 中的空格会让第二个值变成 " image/jpeg",被忽略。
示例:
立即学习“前端免费学习笔记(深入)”;
<input type="file" accept="image/png, image/jpeg, image/webp, .svg+xml">
注意:.svg+xml 是 SVG 的标准 MIME,不是 .svg(后者是扩展名,但部分浏览器识别更稳定);若需兼容旧环境,建议同时写 .svg, image/svg+xml。
- PDF + Word 组合:
accept="application/pdf, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document" - 音频限制:
accept="audio/mpeg, audio/wav, audio/ogg"(避免仅写audio/*,Firefox 可能不生效) - 视频限制:
accept="video/mp4, video/webm",不推荐video/*,移动端 Safari 表现不稳定
服务端必须重新校验 MIME,且不能只看 extension
前端 accept 完全不可信。服务端收到文件后,必须读取文件头(magic bytes)来判断真实 MIME 类型。仅检查扩展名或 Content-Type 请求头是严重漏洞——攻击者可伪造 header 或改扩展名上传恶意脚本。
典型错误做法:
– 用 path.extname() 判断是否为 .png
– 直接信任 req.headers['content-type']
- Node.js 示例(用
file-type库):const fileType = await import('file-type');const result = await fileType.fromBuffer(buffer);if (!['png', 'jpeg', 'webp'].includes(result?.ext)) throw new Error('Invalid image type'); - Python(Flask)建议用
python-magic,而非mimetypes.guess_type() - PHP 推荐
finfo_open(FILEINFO_MIME_TYPE),避免$_FILES['file']['type']
移动端 iOS Safari 的 accept 限制特别松散
iOS 16+ 之前,accept="image/*" 在 Safari 中几乎等同于不限制,用户仍能看到所有图片、视频甚至文档。即使写了 accept="image/png",系统相册里依然能选 JPEG —— 浏览器只做软提示,不拦截。
这意味着:依赖 accept 实现业务逻辑(比如“只允许上传 PNG 做图标”)在 iOS 上大概率失败。必须靠服务端强校验 + 前端 JS 二次校验(读取 blob.type,但同样可伪造,仅作快速反馈)。
- 临时缓解:上传前用
File.type做即时提示(if (file.type !== 'image/png') alert('请上传 PNG 格式');),但不能替代服务端检查 - 真正可靠的方案:上传后服务端解析二进制头,再返回具体错误(如 “文件开头为 JPEG SOI marker,不接受 JPEG”)
accept 是个礼貌的门童,不是保安。真正拦住坏文件的,永远是服务端那几行读 buffer 的代码。



















