refactor: replace custom CSRF and rate-limiting with off-the-shelf libraries
All checks were successful
check / check (push) Successful in 4s
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:
@@ -40,7 +40,7 @@ func testMiddleware(t *testing.T, env string) (*Middleware, *session.Session) {
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
}
|
||||
|
||||
sessManager := newTestSession(t, store, cfg, log)
|
||||
sessManager := newTestSession(t, store, cfg, log, key)
|
||||
|
||||
m := &Middleware{
|
||||
log: log,
|
||||
@@ -55,9 +55,9 @@ func testMiddleware(t *testing.T, env string) (*Middleware, *session.Session) {
|
||||
|
||||
// newTestSession creates a session.Session with a pre-configured cookie store
|
||||
// for testing. This avoids needing the fx lifecycle and database.
|
||||
func newTestSession(t *testing.T, store *sessions.CookieStore, cfg *config.Config, log *slog.Logger) *session.Session {
|
||||
func newTestSession(t *testing.T, store *sessions.CookieStore, cfg *config.Config, log *slog.Logger, key []byte) *session.Session {
|
||||
t.Helper()
|
||||
return session.NewForTest(store, cfg, log)
|
||||
return session.NewForTest(store, cfg, log, key)
|
||||
}
|
||||
|
||||
// --- Logging Middleware Tests ---
|
||||
@@ -326,7 +326,7 @@ func TestMetricsAuth_ValidCredentials(t *testing.T) {
|
||||
store := sessions.NewCookieStore(key)
|
||||
store.Options = &sessions.Options{Path: "/", MaxAge: 86400}
|
||||
|
||||
sessManager := session.NewForTest(store, cfg, log)
|
||||
sessManager := session.NewForTest(store, cfg, log, key)
|
||||
|
||||
m := &Middleware{
|
||||
log: log,
|
||||
@@ -366,7 +366,7 @@ func TestMetricsAuth_InvalidCredentials(t *testing.T) {
|
||||
store := sessions.NewCookieStore(key)
|
||||
store.Options = &sessions.Options{Path: "/", MaxAge: 86400}
|
||||
|
||||
sessManager := session.NewForTest(store, cfg, log)
|
||||
sessManager := session.NewForTest(store, cfg, log, key)
|
||||
|
||||
m := &Middleware{
|
||||
log: log,
|
||||
@@ -406,7 +406,7 @@ func TestMetricsAuth_NoCredentials(t *testing.T) {
|
||||
store := sessions.NewCookieStore(key)
|
||||
store.Options = &sessions.Options{Path: "/", MaxAge: 86400}
|
||||
|
||||
sessManager := session.NewForTest(store, cfg, log)
|
||||
sessManager := session.NewForTest(store, cfg, log, key)
|
||||
|
||||
m := &Middleware{
|
||||
log: log,
|
||||
|
||||
Reference in New Issue
Block a user