diff --git a/internal/controller/post_controller.go b/internal/controller/post_controller.go index a4d2a50..3e83233 100644 --- a/internal/controller/post_controller.go +++ b/internal/controller/post_controller.go @@ -411,25 +411,48 @@ func (ctrl *PostController) UploadImage(c *gin.Context) { ts := time.Now().UnixMilli() var savePath, url string - // JPEG/PNG → WebP 压缩存储(保留原尺寸,quality 80) - if ext == ".jpg" || ext == ".jpeg" || ext == ".png" { + isJPEGPNG := ext == ".jpg" || ext == ".jpeg" || ext == ".png" + isWebP := ext == ".webp" + isGIF := ext == ".gif" + + // 强制解码验证文件是否为有效图片(防伪扩展名、图片投毒),验证失败直接拒绝 + // JPEG/PNG:解码后顺便做 WebP 压缩 + if isJPEGPNG { img, _, err := image.Decode(bytes.NewReader(data)) - if err == nil { - var buf bytes.Buffer - if err := webp.Encode(&buf, img, &webp.Options{Quality: 80}); err == nil { - // 仅当 WebP 比原文件小时才采用,否则回退原格式 - if buf.Len() > 0 && buf.Len() < len(data) { - filename := fmt.Sprintf("%d_%d.webp", uid, ts) - savePath = filepath.Join(storageDir, filename) - if err := os.WriteFile(savePath, buf.Bytes(), 0644); err == nil { - url = "/uploads/posts/" + filename - } + if err != nil { + common.Error(c, http.StatusBadRequest, "图片格式无效,请上传有效的图片文件") + return + } + // WebP 压缩存储(保留原尺寸,quality 80) + var buf bytes.Buffer + if err := webp.Encode(&buf, img, &webp.Options{Quality: 80}); err == nil { + if buf.Len() > 0 && buf.Len() < len(data) { + filename := fmt.Sprintf("%d_%d.webp", uid, ts) + savePath = filepath.Join(storageDir, filename) + if err := os.WriteFile(savePath, buf.Bytes(), 0644); err == nil { + url = "/uploads/posts/" + filename } } } } - // 回退:GIF / WebP / 转换失败 / 转换后反而更大 → 原样存储 + // GIF:仅解码验证,不转换 + if isGIF { + if _, _, err := image.Decode(bytes.NewReader(data)); err != nil { + common.Error(c, http.StatusBadRequest, "图片格式无效,请上传有效的图片文件") + return + } + } + + // WebP:仅解码验证,不重复编码 + if isWebP { + if _, err := webp.Decode(bytes.NewReader(data)); err != nil { + common.Error(c, http.StatusBadRequest, "图片格式无效,请上传有效的图片文件") + return + } + } + + // 原格式存储(WebP / GIF / 转换后反而更大) if savePath == "" { filename := fmt.Sprintf("%d_%d%s", uid, ts, ext) savePath = filepath.Join(storageDir, filename)