真正有效的防篡改必须由后端完成,前端仅能辅助限制、提升体验、增加攻击成本;accept属性仅作ux提示,不参与校验;魔数检测需配合后端深度解析;手动设置multipart/form-data的content-type会导致解析失败;前端校验在js禁用或curl请求时完全失效。

HTML本身做不到防篡改——所有前端手段都可被绕过,真正有效的防护必须由后端完成。前端能做的只是辅助限制、提升体验、增加攻击成本。
accept 属性只影响文件选择器界面
设置 accept=".pdf,.docx" 或 accept="application/pdf" 后,浏览器文件对话框会默认过滤显示类型,但用户仍可手动切换为“所有文件”并选中任意扩展名的文件。这个属性不参与传输,也不校验内容。
- 不要把它当安全措施,仅用作 UX 提示
- 服务端收到文件后,必须忽略请求头里的
Content-Type,改用file命令或python-magic解析真实 MIME 类型 - 如果后端依赖
accept做白名单,攻击者上传shell.php.pdf就可能绕过
FileReader 读取魔数只能筛掉明显异常文件
用 FileReader.readAsArrayBuffer() 读取前 1024 字节,比对 PNG(89 50 4E 47)、JPEG(FF D8 FF)等魔数,能快速拒绝伪造文件,但无法阻止内容级篡改。
- 攻击者可构造合法魔数+恶意 payload 的混合文件(如带 PHP 代码的图片)
- 魔数检测必须配合后端深度解析:例如用
PIL.Image.open()加载图片并捕获异常,或调用identify(ImageMagick)验证结构完整性 - 前端计算的哈希(如 SHA-256)不能用于校验——攻击者可先改文件再重算哈希提交
FormData + fetch 上传时千万别设 Content-Type
用 FormData 构造上传请求时,浏览器会自动添加 Content-Type: multipart/form-data; boundary=...。一旦你手动设置该 header,boundary 就会丢失,导致后端解析失败,req.files 为空。
- 正确写法:
fetch("/upload", { method: "POST", body: formData })—— 不加headers字段 - 错误写法:
headers: { "Content-Type": "multipart/form-data" }—— 这会让整个请求体变成无效格式 - 若需传递额外信息(如预期哈希),用自定义 header:
headers: { "X-Expected-Hash": "sha256=abc123" },服务端仅作日志或比对参考,不可替代重算
最容易被忽略的一点是:前端任何校验逻辑在禁用 JavaScript 或直接发 curl 请求时全部失效。哪怕你加了魔数检查、大小拦截、文件名清洗,攻击者只要绕过浏览器,就能把任意二进制数据发到你的接口。所以,后端收到文件后的第一行代码,就该是重算哈希或解析真实类型——这才是防篡改真正的起点。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











