把一段脚本改名成 avatar.jpg 上传,接口返回上传成功,访问返回的地址直接执行了里面的代码,后缀检查一点作用都没起。日志里能对上时间点,这种反而好排。

校验看的是文件名后缀和请求头里的 Content-Type,这两样都由客户端说了算,真正的类型要看文件开头几个字节,还得让存储目录不可执行。这一点先确认清楚,后面就不用反复试。

file --mime-type uploads/avatar.jpg
xxd -l 8 uploads/avatar.jpg
# 期望前两字节是 ff d8,不是 3c 3f 70 68 70

「上传内容校验」确认了原因之后,改动尽量只碰那一处,顺手改的东西后面最容易出问题。先做最小复现,能稳定跑出来的问题,排查成本会低一个数量级。

别只看报错的最后一行,往上看几行,真正的起因通常在上面。

处理上按这个顺序:读文件头几个字节比对魔数,只放行白名单里的类型;上传目录里关掉脚本解析,文件另外存到对象存储;服务端再走一次图片解码流程,解不开的直接丢弃掉。

结果对不对很好判断,改名的脚本文件上传时返回 415,正常的 jpg 图片仍然能上传并访问。

作者 9823189