64 lines
2.1 KiB
Go
64 lines
2.1 KiB
Go
// Package csrf
|
|
// Path: /internal/platform/csrf
|
|
// File: csrf.go
|
|
//
|
|
// Purpose
|
|
//
|
|
// Centralized CSRF protection wrapper using justinas/nosurf.
|
|
// Applies default CSRF protections across the entire HTTP handler tree
|
|
// after SCS session load/save wrapping.
|
|
//
|
|
// Responsibilities (as implemented here)
|
|
// 1. Construct a nosurf middleware handler over the provided http.Handler.
|
|
// 2. Configure the base CSRF cookie using values from the App configuration.
|
|
// 3. Enforce HttpOnly and SameSite=Lax defaults.
|
|
// 4. Enable Secure flag automatically in production mode.
|
|
//
|
|
// HTTP stack order (per bootstrap)
|
|
//
|
|
// Gin Router → SCS LoadAndSave → CSRF Wrapper → http.Server
|
|
//
|
|
// Design notes
|
|
// - The nosurf package automatically:
|
|
// - Inserts CSRF token into responses (e.g., via nosurf.Token(c.Request))
|
|
// - Validates token on state-changing requests (POST, PUT, etc.)
|
|
// - CSRF cookie name is configurable via config.Config.
|
|
// - Secure flag is tied to cfg.HttpServer.ProductionMode (recommended).
|
|
// - Global protection: all routed POSTs are covered automatically.
|
|
//
|
|
// TODOs (observations from current implementation)
|
|
// - Expose helper to fetch token into Gin templates via context key.
|
|
// - Consider SameSiteStrictMode once OAuth/external logins are defined.
|
|
// - Add domain and MaxAge settings for more precise control.
|
|
// - Provide per-route opt-outs if needed for webhook endpoints.
|
|
//
|
|
// Change log
|
|
//
|
|
// [2025-10-29] Documentation updated to reflect middleware position and cookie policy.
|
|
package csrf
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"synlotto-website/internal/platform/config"
|
|
|
|
"github.com/justinas/nosurf"
|
|
)
|
|
|
|
// Wrap applies nosurf CSRF middleware to the given handler,
|
|
// configuring the CSRF cookie based on App configuration.
|
|
//
|
|
// Caller must ensure this is positioned *outside* SCS LoadAndSave
|
|
// so CSRF can access session data when generating/validating tokens.
|
|
func Wrap(h http.Handler, cfg config.Config) http.Handler {
|
|
cs := nosurf.New(h)
|
|
cs.SetBaseCookie(http.Cookie{
|
|
Name: cfg.CSRF.CookieName,
|
|
Path: "/",
|
|
HttpOnly: true,
|
|
Secure: cfg.HttpServer.ProductionMode,
|
|
SameSite: http.SameSiteLaxMode,
|
|
})
|
|
return cs
|
|
}
|