Decision: should IPv6 rate-limit keys bucket by /64 rather than per-address? #125
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Raised by the independent review of #122. Pre-existing and inherent to per-IP keying, so it was correctly out of scope there — but it is worth deciding before 1.0.0, because it limits how much the receiver rate limit is actually worth over IPv6.
Rate-limit keys are per-address, i.e. per
/128for IPv6. A client with a routed/64— which is the normal residential and mobile IPv6 allocation — can rotate source addresses and mint a fresh bucket per request. All three limiters are affected; the unauthenticated receiver endpoint is the one that matters.Net effect: #88 closed header spoofing, but for IPv6 clients the limit is still evadable at the network layer, without any spoofing at all.
Needs your call because bucketing by prefix trades precision for coverage.
Options
/64, IPv4 by/32(unchanged). Matches how the allocation boundary actually works. One subscriber gets one bucket.Recommendation: option 1. It is the conventional choice, needs no new configuration surface, and matches the threat — the attacker gets addresses in
/64units, so that is the unit worth limiting. The cost is that genuine distinct clients sharing a/64share a bucket, which for a webhook receiver is the correct conservative direction. Option 2 adds a knob that nobody will tune correctly. Option 3 leaves the control half-working on the address family that is increasingly the default.Done-criteria once decided
/64for IPv6 addresses and the full address for IPv4./64share a bucket, and two in different/64s do not.Note this touches
internal/middleware/ratelimit.go, the same file as #124 — sequence them rather than running both at once.