Help us shape the future of Go! Take the 2026 Go Developer Survey

ratelimit

package
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 11, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package ratelimit provides a small token-bucket rate-limit middleware used to protect anonymous attack surfaces (login, enroll) from brute-force / password-spray.

The Limiter is keyed by a caller-supplied function (IP, IP+username, etc.) so the same primitive can fan out to per-endpoint policies.

Index

Constants

View Source
const DefaultMaxBuckets = 100_000

DefaultMaxBuckets is the cap on the per-key map size. Once exceeded, new keys all share a single overflow bucket, so an attacker churning arbitrary keys (X-Forwarded-For spoofing or a similar primitive in a future surface) cannot grow the limiter's memory footprint unbounded.

Variables

This section is empty.

Functions

func KeyByIP

func KeyByIP(r *http.Request) string

KeyByIP is a convenience keyFn for IP-based rate limiting. Returns the direct connection peer's IP via utils.RemoteIP, NEVER the value from X-Forwarded-For or X-Real-IP.

Why not utils.GetIP: when --trusted-proxies is configured GetIP walks the X-Forwarded-For chain right-to-left and returns the first untrusted hop. Most edge proxies (nginx default, ELB, Cloudflare) *append* to X-Forwarded-For rather than replacing it, so an attacker who sets X-Forwarded-For: 1.2.3.4 in their request gets that value echoed back as the right-most-untrusted hop. Rotating header values then cycles bucket keys and defeats the rate limit.

Keying on the TCP peer the trusted proxy itself terminates against closes the bypass: that address is determined by the proxy's network position and is unspoofable from the client side.

Types

type Limiter

type Limiter struct {
	// contains filtered or unexported fields
}

Limiter is a sharded map of token buckets keyed by an arbitrary string. Buckets age out after `evictAfter` of inactivity so the map doesn't grow unbounded. Eviction is amortized — the full O(N) scan runs at most once per `evictAfter/2` so a single hot-path Allow doesn't pay the cost. When the map exceeds maxBuckets, new keys collapse onto a shared overflow bucket; the spray still gets rate-limited (just not per-key) and memory stays bounded.

func New

func New(burst int, per, evictAfter time.Duration) *Limiter

New returns a Limiter that allows up to `burst` events per key over `per`, with steady-state refill at `burst/per`. evictAfter is the inactivity window after which a key's bucket is forgotten — pick something larger than `per` so genuine retries don't reset their bucket.

The bucket map is capped at DefaultMaxBuckets entries. Operators that need a different cap can construct via NewWithCap.

func NewFromConfig added in v0.5.6

func NewFromConfig(cfg config.YAMLConfigurationRateLimit) *Limiter

NewFromConfig returns a Limiter from service configuration values.

func NewWithCap

func NewWithCap(burst int, per, evictAfter time.Duration, maxBuckets int) *Limiter

NewWithCap is New with an explicit ceiling on the per-key map size.

func (*Limiter) Allow

func (l *Limiter) Allow(key string) bool

Allow returns true if the supplied key can perform one event under the current bucket state. Side-effect: the bucket is created on first use and idle buckets are GC'd opportunistically (at most once per evictInterval to keep the hot path constant-time). When the map is already at maxBuckets and the key has no existing bucket, the call falls back to the shared overflow bucket so memory stays bounded.

func (*Limiter) HTTPMiddleware

func (l *Limiter) HTTPMiddleware(keyFn func(*http.Request) string, onReject func(*http.Request, string)) func(http.Handler) http.Handler

HTTPMiddleware returns a middleware that rejects requests with 429 when `keyFn(r)` exceeds the limit. keyFn is responsible for choosing the dimension (e.g., utils.GetIP(r), or `utils.GetIP(r) + ":" + username`).

onReject is invoked synchronously when a request is rejected — use it to emit an audit-log entry. May be nil.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL