只设router.maxmultipartmemory无效,因它仅限制内存缓存(默认32mb),不拦截请求体流式读取;攻击者可发500mb表单耗尽i/o和cpu。必须在每个post/put handler开头用http.maxbytesreader硬截断总请求体,且须早于c.postform、c.formfile等任何读取操作。

直接结论:只设 router.MaxMultipartMemory 不起作用,必须在路由 handler 内部用 http.MaxBytesReader 包裹 c.Request.Body,且所有接收表单的 POST/PUT 路由都得加。
为什么 MaxMultipartMemory 限制不了攻击流量
router.MaxMultipartMemory 只控制解析 multipart 表单时内存中缓存的大小(默认 32MB),不拦截原始请求体。攻击者发一个 500MB 的恶意表单,Gin 会把超出部分写入临时磁盘文件,但整个 body 已流式读入、CPU 和 I/O 已被耗尽——这正是 DDoS 攻击要的效果。
- 它不是 HTTP 层限流,而是解析层“缓存策略”
- 设成
1(单位是 MiB)只会让大文件转存临时文件,不会拒绝请求 - 错误日志里通常看不到明显报错,服务却响应迟缓甚至 OOM
正确做法:用 http.MaxBytesReader 硬截断总请求体
必须在每个接收表单的 handler 开头,用标准库的 http.MaxBytesReader 包裹原始 body,强制在流式读取阶段就中断超限请求。
- 放在
c.PostForm、c.FormFile、c.ShouldBind之前,否则这些方法会先触发完整读取 - 值按业务最大合理值 +20% 设定,比如上传接口允许 5MB 文件 → 设
6 * 1024 * 1024 - 不只是 upload 路由,登录、注册、反馈等所有
POST表单路由都必须加 - 示例:
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, 6*1024*1024)
PostForm 返回空或截断?那是 ParseMultipartForm 失败了
c.PostForm 不主动解析,它只读 formCache;而 cache 是否填充,取决于 r.ParseForm() 或 r.ParseMultipartForm() 是否成功执行。一旦请求体超 MaxMultipartMemory,解析就会静默失败,cache 为空 → 所有 c.PostForm("xxx") 都返回空字符串,不是截断,是“根本没解析”。
- 不要依赖
c.PostForm做长度判断,它不可靠 - 字段级长度校验必须用
ShouldBind+ 结构体 tag(如binding:"max=1000") - 若需手动检查,应在
ParseMultipartForm后读c.Request.MultipartForm.Value["content"]长度 - 更安全的做法:中间件里用
io.LimitReader(c.Request.Body, 2 统一约束,后续所有解析都受控
容易忽略的关键点
很多人只在 upload 路由加防护,但攻击者会轮番打登录、注册等任意 POST 接口。只要没加 http.MaxBytesReader,这些路由就是裸奔状态。另外,ShouldBind 虽能校验字段长度,但它会先把整个 body 读进内存——所以前置的流式截断不能省,否则校验还没开始,服务已经卡死。











