← 中文资源

简体中文版本

HTTP 服务器读写超时加固

为 HTTP 服务器配置全套超时:头部、读、写、空闲四段独立时限加头部体积上限,慢速攻击无法长期占用连接。

阅读英文原文

示例说明

默认 http.Server 的多数超时是零——无限等待。慢速攻击正是利用这一点:每个连接以每分钟一个字节的速度发请求,几千个连接就能耗尽句柄池。四段超时各有分工:ReadHeaderTimeout 拦截慢速头部、ReadTimeout 约束请求体、WriteTimeout 限制响应时长、IdleTimeout 回收 keep-alive 空闲连接——组合起来慢速攻击彻底失效。

技术要点

  • 四段超时覆盖连接全生命周期
  • MaxHeaderBytes 封顶头部体积
  • 方法校验前置减少无效处理

代码解读

newHardenedServer 一次性声明全部时限:头部五秒、读十秒、写三十秒、空闲两分钟,头部上限一兆字节。处理器先校验方法并设置 Allow 头——把错误在最早阶段礼貌拒绝。ListenAndServe 的错误直接致命退出,配置错误不该静默。

使用建议

写超时要大于最慢合法响应的耗时,SSE 等长连接需单独豁免。反向代理场景超时要全链路形成漏斗。生产再加限流与并发连接数上限。

代码示例

package main

import (
	"fmt"
	"log"
	"net/http"
	"time"
)

func newHardenedServer(addr string) *http.Server {
	return &http.Server{
		Addr:              addr,
		ReadHeaderTimeout: 5 * time.Second, // 头部必须快速到达
		ReadTimeout:       10 * time.Second,
		WriteTimeout:      30 * time.Second,
		IdleTimeout:       120 * time.Second,

		MaxHeaderBytes: 1 << 20, // 头部上限 1MiB

		Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			if r.Method != http.MethodPost {
				w.Header().Set("Allow", http.MethodPost)
				http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
				return
			}
			fmt.Fprintln(w, "accepted")
		}),
	}
}

func main() {
	srv := newHardenedServer(":8080")
	log.Fatal(srv.ListenAndServe())
}