go应用层防ddos的核心是恶意请求前置失败而非拦截全部流量,需用rate.limiter按ip复用限流、atomic计数限制长连接、设置http超时并禁用keep-alive滥用,同时结合内核调优与iptables等前置防护。

Go 应用层防 DDoS 的核心不是“挡住所有流量”,而是让恶意请求在抵达业务逻辑前就失败,同时不拖垮正常连接和 goroutine 调度。标准库和生态提供了足够轻量、可控的工具,关键在于选对时机和粒度。
用 golang.org/x/time/rate 做 IP 级请求限流
这是最常用也最容易误用的一环。令牌桶必须按 IP 维护,且不能直接用 rate.Limiter 全局单例——否则所有 IP 共享同一个桶,等于没限。
-
NewIPRateLimiter(1, 5)表示每秒最多 1 个请求、最多积压 5 个令牌;对 API 接口来说偏保守,可调为(10, 20);对登录页等高敏感路径建议更严(如(2, 3)) - 注意
r.RemoteAddr可能带端口(如192.168.1.100:54321),需用strings.Split(r.RemoteAddr, ":")[0]提取纯 IP,否则同一 IP 多连接会被误判为多个客户端 - 不要在
http.HandlerFunc内每次 new 一个rate.Limiter,会导致内存泄漏和锁竞争;必须复用结构体 +sync.RWMutex管理 map
对长连接服务(如 RTMP、WebSocket)限制并发数
HTTP 短连接靠限流即可,但 Livego、自研信令服务这类长连接场景,攻击者建一堆空连接就能耗尽 net.Conn 和 goroutine,光限请求频率没用。
- 在
net.Listener.Accept()后立刻检查当前活跃连接数,超限时直接conn.Close()并记录日志;不要等到握手完成再判断 - Livego 的
max_connections: 1000是配置项,但它只作用于内部统计,不自动拒绝新连接;需在protocol/rtmp/accept.go类似位置手动加守门逻辑 - 避免用
sync.WaitGroup或全局计数器做连接统计——高并发下Add/Done争抢严重;改用atomic.Int64的Load/Store/Add
启用连接级超时并关闭 Keep-Alive 滥用
SYN Flood 或慢速 HTTP 攻击(如 Slowloris)不发完整请求,只维持半开或低速发送,耗尽服务器连接表或 read buffer。
- 在
http.Server中显式设置:ReadTimeout: 5 * time.Second、WriteTimeout: 10 * time.Second、IdleTimeout: 30 * time.Second;不设IdleTimeout时默认 0(永不超时) - 对非浏览器客户端(如 IoT 设备、爬虫),可考虑禁用 Keep-Alive:
Header.Set("Connection", "close"),减少连接复用被滥用的风险 - 注意:超时值不能低于业务最长处理时间,否则会误杀正常请求;建议先用
pprof观察 P95 处理时长,再设超时
别把防御全押在应用层
Go 应用层能做的有限:它无法拦截 SYN 包、无法过滤 UDP 洪水、也无法应对带宽打满的 volumetric 攻击。这些必须交由更前置的环节。
- 内核参数必须调优:
net.ipv4.tcp_syncookies = 1开启 SYN Cookie,net.ipv4.tcp_max_syn_backlog = 65536加大半连接队列 - 哪怕只是开发环境,也该用
iptables或nftables做基础防护,比如单 IP 每秒新建连接超 30 个就 DROP:nft add rule ip filter input tcp dport 8080 ct state new limit rate 30/second counter drop - XDP 层(如用 Go eBPF 加载)确实能最早期丢包,但要求内核 ≥ 4.15 且需 C 编写 eBPF 程序;对多数业务服务来说,投入产出比远不如配好 CDN + WAF + 基础 iptables











