🔐 后台上传图片:安全校验与自动转 AVIF
最后更新:2026-10-02
🎯 设计目标
| 诉求 | 实现方式 |
|---|---|
| 体积最小、加载最快 | 浏览器端 Canvas 把图片转成 image/avif(优先)/ image/webp 再上传 |
| 防 XSS / 伪装文件 | 服务端用 image.DecodeConfig + 文件魔数校验真实格式,伪装文件直接拒收删除 |
| 部署零额外依赖 | 不用服务端 CGO(客户机无 gcc),转码完全在浏览器,Windows 部署无忧 |
| 低版本浏览器防护 | 不支持 AVIF 编码的浏览器禁止进入 /admin,提示更新浏览器 |
| logo / 微信二维码不压缩 | 这两个 input 标记 data-nocompress,原图直传、保持清晰度 |
⚙️ 浏览器端转换规则
后台所有「上传图片」的 <input type=file> 都会被前端脚本拦截,流程如下:
| 步骤 | 行为 |
|---|---|
| 1. 读取 | 用 FileReader 读入,画到 canvas |
| 2. 缩放 | 等比缩放到最大 1000×900(超出则缩小,不足则保持原尺寸) |
| 3. 编码 | 优先 canvas.toBlob('image/avif');浏览器不支持 AVIF 时回退 image/webp,再回退 image/png |
| 4. 提交 | 把得到的 Blob 当作文件上传到 /admin/upload/image |
注意:带 data-nocompress 的输入框(站点 logo、企业微信二维码)会跳过上述缩放与重编码,原图直接上传,保证图标清晰不被压糊。
富文本编辑器(wangeditor)内插图也走同一套转换:通过 customUpload 钩子先调 window.cmsCompressImage,再 fetch 上传,所以正文配图同样会被转 AVIF。
📋 上传白名单
后台「上传图片」仅允许以下扩展名;其余一律拒绝(返回错误,不落盘)。
| 类别 | 扩展名 |
|---|---|
| 允许上传 | .jpg .jpeg .png .gif .webp .avif |
| 已移除 | .svg(有 XSS 注入风险)、.bmp(体积大、无压缩) |
这与「前台可引用的静态资源扩展名」不是一回事——.svg 虽不能作为前台模板引用(见 模板打包规范),但仍可作为静态资源手动放进 /static/ 引用,只是不能经后台上传。
🛡️ 服务端真实类型校验(兜底)
前端能被绕过(直接构造请求),所以服务端对每张上传图做真实格式校验,这是安全闭环的最后一环:
- JPG / PNG / GIF:用
image.DecodeConfig真正解码一帧,拿不到尺寸即判为伪造成功拒绝 - WebP:校验文件头魔数
RIFF....WEBP - AVIF:校验文件头
ftyp后跟avif/avis - 校验不通过的伪装文件:立即
os.Remove删除,不上传目录、不入库
因此即便攻击者伪造 .jpg 后缀塞入恶意内容,也会被服务端拦截,不会存进网站目录。
🚪 AVIF 浏览器门槛(/admin 守卫)
进入后台前,页面会执行一次真编码能力探测(不只是特性判断,而是实际 canvas.toBlob('image/avif') 看是否真能产出 type==='image/avif' 的 Blob),防止浏览器静默回退成 PNG 却自认支持。
| 探测结果 | 用户看到什么 |
|---|---|
| 支持 AVIF 编码 | 正常显示登录框 / 后台,可继续操作 |
| 不支持 | 全屏红字遮罩「请更新浏览器到最新版 Chrome / Edge / Firefox」,隐藏登录框;已进入后台的页面顶部显示红条并禁用上传控件 |
这一步保证:凡是能进 /admin 的浏览器,都具备把图片转 AVIF 的能力,从而让整条「浏览器端压缩转 AVIF」链路成立。
🔧 可调参数(环境变量)
压缩尺寸与质量可通过环境变量覆盖(缺省取下方默认值)。
默认值 1000×900、质量 82 已在源码中写死为 fallback,不设置也生效。改完后重启服务进程即可生效(这是服务端配置,不是模板热加载)。
❓ 常见疑问
| 疑问 | 解答 |
|---|---|
| 服务器要装 ImageMagick / libvips 吗? | 不需要。转码全在浏览器,服务端只校验,零额外依赖。 |
| 客户上传的是 PNG,前台会变成 AVIF 吗? | 会。浏览器转成 AVIF(不支持则 WebP)后上传,落盘的就是 AVIF。 |
| logo 被压糊了怎么办? | 站点 logo、企业微信 两个 input 已标记 data-nocompress,原图直传不缩放。 |
| 老浏览器上传报错? | 属正常防护——提示更新浏览器即可,这是安全设计。 |
| 直接 POST 上传接口能绕过前端吗? | 不能。服务端真实类型校验会拦截伪装文件并删除。 |
Gitl.cn云建站 SaaS