fix(v2): 限流按 socket 对端 IP(SetTrustedProxies(nil),伪造 XFF 失效)+ 桶 map 硬上限防 OOM
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// jiu 反馈波安全 review item 2:攻击者可用无限伪造 IP(哪怕已按 SetTrustedProxies(nil)
|
||||
// 锁死了 XFF 伪造这条路,真实的分布式来源/僵尸网络仍能刷出海量不同 socket 源 IP)撑爆
|
||||
// buckets map。这条白盒测试直接灌入超过 maxBuckets 的不同 IP,断言 map 有硬上限、
|
||||
// 不会无限增长,且超限后的新 IP 被安全拒绝(而不是继续建桶或 panic)。
|
||||
func TestIPRateLimiterBucketMapBounded(t *testing.T) {
|
||||
rl := NewIPRateLimiter(1)
|
||||
|
||||
for i := 0; i < maxBuckets; i++ {
|
||||
rl.allow(fmt.Sprintf("spoofed-ip-%d", i))
|
||||
}
|
||||
|
||||
rl.mu.Lock()
|
||||
sizeAtCap := len(rl.buckets)
|
||||
rl.mu.Unlock()
|
||||
if sizeAtCap != maxBuckets {
|
||||
t.Fatalf("灌满硬上限后 map size 应等于 maxBuckets(%d), got %d", maxBuckets, sizeAtCap)
|
||||
}
|
||||
|
||||
// 硬上限已满、且都是刚创建的活跃桶(sweep 回收不了任何一个):新 IP 应被拒绝
|
||||
// (安全侧,宁可误限也不无界建桶),不应放行/建桶。
|
||||
for i := 0; i < 100; i++ {
|
||||
if rl.allow(fmt.Sprintf("overflow-ip-%d", i)) {
|
||||
t.Fatalf("硬上限已满时,超限的新 IP(overflow-ip-%d)应被拒绝而非放行", i)
|
||||
}
|
||||
}
|
||||
|
||||
rl.mu.Lock()
|
||||
sizeAfterOverflow := len(rl.buckets)
|
||||
rl.mu.Unlock()
|
||||
if sizeAfterOverflow > maxBuckets {
|
||||
t.Fatalf("超限请求后 buckets map 不应继续增长: size=%d max=%d", sizeAfterOverflow, maxBuckets)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user