CSRF
Cross-Site Request Forgery (CSRF, a veces pronunciado “sea-surf”, o XSRF) es un tipo de exploit malicioso en el que se transmiten comandos no autorizados desde un usuario en el que un sitio web confía.
e.Use(middleware.CSRF())Cómo funciona
Sección titulada «Cómo funciona»El middleware CSRF soporta el header
Sec-Fetch-Site
como un enfoque moderno de defensa en profundidad para la
protección CSRF,
implementando la Fetch Metadata API recomendada por OWASP junto al mecanismo tradicional
basado en tokens.
Los navegadores modernos envían automáticamente el header Sec-Fetch-Site con cada request,
indicando la relación entre el origin del request y el destino. El middleware usa esto para
tomar una decisión de seguridad:
same-originonone: permitido (coincidencia exacta de origin o navegación directa del usuario)same-site: vuelve a la validación por token (por ejemplo, de subdominio a dominio principal)cross-site: bloqueado por defecto con un error403para métodos inseguros (POST, PUT, DELETE, PATCH)
Para navegadores que no envían este header (navegadores más antiguos), el middleware vuelve sin interrupciones a la protección CSRF tradicional basada en tokens.
Dos opciones ajustan el comportamiento de Sec-Fetch-Site:
TrustedOrigins []string: allowlist de origins específicos para requests cross-site (útil para callbacks OAuth, webhooks)AllowSecFetchSiteFunc func(c *echo.Context) (bool, error): lógica personalizada para validación same-site/cross-site
e.Use(middleware.CSRFWithConfig(middleware.CSRFConfig{ // Allow OAuth callbacks from a trusted provider. TrustedOrigins: []string{"https://oauth-provider.com"},
// Custom validation for same-site/cross-site requests. AllowSecFetchSiteFunc: func(c *echo.Context) (bool, error) { // Your custom authorization logic here. return validateCustomAuth(c), nil // return true, err // blocks the request with an error // return true, nil // allows the request through // return false, nil // falls back to legacy token logic },}))Protección basada en tokens
Sección titulada «Protección basada en tokens»e := echo.New()e.Use(middleware.CSRFWithConfig(middleware.CSRFConfig{ TokenLookup: "header:X-XSRF-TOKEN",}))El ejemplo anterior extrae el token CSRF del header de request X-XSRF-TOKEN.
Leer el token desde una cookie en su lugar:
middleware.CSRFWithConfig(middleware.CSRFConfig{ TokenLookup: "cookie:_csrf", CookiePath: "/", CookieDomain: "example.com", CookieSecure: true, CookieHTTPOnly: true, CookieSameSite: http.SameSiteStrictMode,})Acceder al token CSRF
Sección titulada «Acceder al token CSRF»- Server-side: el token está disponible desde el contexto bajo
ContextKeyy se puede pasar al cliente mediante un template. - Client-side: el token se puede leer desde la cookie CSRF.
Configuración
Sección titulada «Configuración»type CSRFConfig struct { // Skipper defines a function to skip middleware. Skipper Skipper
// TrustedOrigins permits any request with a `Sec-Fetch-Site` header whose `Origin` // header exactly matches one of the listed values. Values should be formatted as // the Origin header: "scheme://host[:port]". TrustedOrigins []string
// AllowSecFetchSiteFunc allows custom behaviour for `Sec-Fetch-Site` requests that // are about to fail with a CSRF error, to be allowed or replaced with a custom // error. Applies to `same-site` and `cross-site` values. AllowSecFetchSiteFunc func(c *echo.Context) (bool, error)
// TokenLength is the length of the generated token. // Optional. Default value 32. TokenLength uint8
// TokenLookup is a string in the form "<source>:<name>" or // "<source>:<name>,<source>:<name>" used to extract the token from the request. // Optional. Default value "header:X-CSRF-Token". // Possible values: // - "header:<name>" or "header:<name>:<cut-prefix>" // - "query:<name>" // - "form:<name>" // Multiple sources example: "header:X-CSRF-Token,query:csrf". TokenLookup string `yaml:"token_lookup"`
// Generator defines a function to generate the token. // Optional. Defaults to randomString(TokenLength). Generator func() string
// ContextKey is the key under which the generated CSRF token is stored in the context. // Optional. Default value "csrf". ContextKey string
// CookieName is the name of the CSRF cookie that stores the token. // Optional. Default value "_csrf". CookieName string
// CookieDomain is the domain of the CSRF cookie. // Optional. Default value none. CookieDomain string
// CookiePath is the path of the CSRF cookie. // Optional. Default value none. CookiePath string
// CookieMaxAge is the max age (in seconds) of the CSRF cookie. // Optional. Default value 86400 (24h). CookieMaxAge int
// CookieSecure indicates whether the CSRF cookie is secure. // Optional. Default value false. CookieSecure bool
// CookieHTTPOnly indicates whether the CSRF cookie is HTTP only. // Optional. Default value false. CookieHTTPOnly bool
// CookieSameSite indicates the SameSite mode of the CSRF cookie. // Optional. Default value SameSiteDefaultMode. CookieSameSite http.SameSite
// ErrorHandler defines a function that returns custom errors. ErrorHandler func(c *echo.Context, err error) error}Configuración por defecto
Sección titulada «Configuración por defecto»var DefaultCSRFConfig = CSRFConfig{ Skipper: DefaultSkipper, TokenLength: 32, TokenLookup: "header:" + echo.HeaderXCSRFToken, ContextKey: "csrf", CookieName: "_csrf", CookieMaxAge: 86400, CookieSameSite: http.SameSiteDefaultMode,}Ejemplo completo
Sección titulada «Ejemplo completo»Hay un ejemplo completo y ejecutable disponible en el recetario de echox.