refactor: replace custom CSRF and rate-limiting with off-the-shelf libraries
All checks were successful
check / check (push) Successful in 4s

Replace custom CSRF middleware with gorilla/csrf and custom rate-limiting
middleware with go-chi/httprate, as requested in code review.

CSRF changes:
- Replace session-based CSRF tokens with gorilla/csrf cookie-based
  double-submit pattern (HMAC-authenticated cookies)
- Keep same form field name (csrf_token) for template compatibility
- Keep same route exclusions (webhook/API routes)
- In dev mode, mark requests as plaintext HTTP to skip Referer check

Rate limiting changes:
- Replace custom token-bucket rate limiter with httprate sliding-window
  counter (per-IP, 5 POST requests/min on login endpoint)
- Remove custom IP extraction (httprate.KeyByRealIP handles
  X-Forwarded-For, X-Real-IP, True-Client-IP)
- Remove custom cleanup goroutine (httprate manages its own state)

Kept as-is:
- SSRF prevention code (internal/delivery/ssrf.go) — application-specific
- CSRFToken() wrapper function — handlers unchanged

Updated README security section and architecture overview to reflect
library choices.
This commit is contained in:
clawbot
2026-03-10 10:05:38 -07:00
parent 5c69efb5bc
commit 0829f9a75d
11 changed files with 126 additions and 317 deletions

View File

@@ -88,34 +88,3 @@ func TestLoginRateLimit_IndependentPerIP(t *testing.T) {
handler.ServeHTTP(w2, req2)
assert.Equal(t, http.StatusOK, w2.Code, "different IP should not be affected")
}
func TestExtractIP_RemoteAddr(t *testing.T) {
t.Parallel()
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.RemoteAddr = "192.168.1.100:54321"
assert.Equal(t, "192.168.1.100", extractIP(req))
}
func TestExtractIP_XForwardedFor(t *testing.T) {
t.Parallel()
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.RemoteAddr = "10.0.0.1:1234"
req.Header.Set("X-Forwarded-For", "203.0.113.50, 70.41.3.18, 150.172.238.178")
assert.Equal(t, "203.0.113.50", extractIP(req))
}
func TestExtractIP_XRealIP(t *testing.T) {
t.Parallel()
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.RemoteAddr = "10.0.0.1:1234"
req.Header.Set("X-Real-IP", "203.0.113.50")
assert.Equal(t, "203.0.113.50", extractIP(req))
}
func TestExtractIP_XForwardedForSingle(t *testing.T) {
t.Parallel()
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.RemoteAddr = "10.0.0.1:1234"
req.Header.Set("X-Forwarded-For", "203.0.113.50")
assert.Equal(t, "203.0.113.50", extractIP(req))
}