go 的 `http.request.body` 不会自动全量缓冲,服务器在接收到请求头后立即调用 `servehttp`,而请求体按需读取;若不主动读取或限制读取超时,慢速攻击(如 slowloris)可能导致连接长期占用和内存/连接数耗尽。
在 Go 的 net/http 包中,http.Request.Body 是一个实现了 io.ReadCloser 接口的流式读取器(通常是 *io.LimitedReader 包裹的底层网络连接),它本身不预先缓存整个请求体。这意味着:
最直接、有效的防护不是依赖“是否缓冲”,而是通过 连接级与读取级超时 来限制恶意行为:
server := &http.Server{
Addr: ":8080",
Handler: &MyHandler{},
ReadTimeout: 5 * time.Second, // 从连接建立到读完 request header 的总时间上限
ReadHeaderTimeout: 2 * time.Second, // 仅限制读取 header 的时间(Go 1.8+)
WriteTimeout: 10 * time.Second,
IdleTimeout: 30 * time.Second,
}
log.Fatal(server.ListenAndServe())? 关键说明: ReadTimeout 从 Accept 开始计时,覆盖 header 解析 + body 读取全过程; ReadHeaderTimeout 更精准,仅约束 header 解析阶段(防止 header 慢速攻击); 即使 handler 内部未读 r.Body,超时仍会触发连接关闭,避免资源长期悬挂。
此外,在业务逻辑中也应主动、有界地消费请求体,尤其对大文件上传或未知大小的 POST:
func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
// 限制最大读取量(例如 10MB),防止 OOM
limitedBody := http.MaxBytesReader(w, r.Body, 10<<20)
data, err := io.ReadAll(limitedBody)
if err != nil {
http.Error(w, "Request body too large or read error", http.StatusRequestEntityTooLarge)
return
}
// 处理 data...
}
}遵循以上实践,即可在保持 Go 高并发优势的同时,有效抵御 Slowloris 及类似资源耗尽型攻击。