应使用http.Request.FormFile解析multipart/form-data上传文件,避免手动读取body;服务端须校验Content-Type、文件头魔数及大小,ParseMultipartForm需提前设置。

接收文件上传请求
使用 http.Request.FormFile 获取前端提交的文件,它会自动解析 multipart/form-data 请求体。注意不要直接用 req.MultipartReader() 或手动读取 body,否则可能破坏表单其他字段的解析。
示例代码:
file, header, err := r.FormFile("upload")
if err != nil {
http.Error(w, "文件未选择或解析失败", http.StatusBadRequest)
return
}
defer file.Close()
验证文件基础属性
仅靠前端 accept 或文件后缀名无法保证安全,必须在服务端校验:
立即学习“go语言免费学习笔记(深入)”;
-
检查 Content-Type:如限制图片上传,可接受
image/jpeg、image/png,但需注意 MIME 类型由客户端提供,不可全信 -
读取文件头(Magic Number):用
file.Read()读前 512 字节,调用http.DetectContentType()或比对已知魔数(如 PNG 是89 50 4E 47) -
限制文件大小:在 ParseMultipartForm 前设置
r.ParseMultipartForm(32 (32MB),防止内存耗尽;再结合header.Size做二次判断 -
过滤危险扩展名:维护白名单(如
["jpg", "jpeg", "png", "pdf"]),从header.Filename提取后缀并小写标准化,不依赖header.Header.Get("Content-Type")
安全存储文件
避免将用户控制的文件名直接用于磁盘路径,防止路径遍历(如 ../../etc/passwd)和覆盖系统文件:
-
重命名文件:用随机字符串(
uuid.New().String())或哈希(sha256.Sum256(fileBytes).Hex())生成唯一文件名 -
分离存储路径:固定上传目录(如
"./uploads/"),拼接时用filepath.Join(uploadDir, safeName),禁止拼接原始 filename -
设置目录权限:确保上传目录不可执行(Linux 下
chmod 755 uploads/),Web 服务器不直接提供该目录的 HTTP 访问 - 保存元数据到数据库:记录原始名、大小、MIME、存储路径、上传时间、所属用户等,便于审计与清理
防范常见攻击
除基础校验外,还需主动防御典型风险:
-
防 ZIP 溢出 / 软链接攻击:若允许 ZIP 上传,解压前检查内部路径是否含
"../"或绝对路径;禁用符号链接解析 -
防恶意脚本注入:对 PDF、Office 文档等,可调用外部工具(如
pdfinfo、libreoffice --headless)做轻量解析,或使用专用库(unioffice)验证结构合法性 - 防 DoS 攻击:限制单 IP 单位时间上传次数;对大文件启用分块上传 + 签名验证(如预签名 URL),避免长连接阻塞
- 防内容污染:上传后立即用杀毒库(如 ClamAV 的 Go 绑定)扫描,或集成云查毒 API










