fiber/docs/api/middleware/csrf.md

17 KiB
Raw Blame History

id
csrf

CSRF

CSRF middleware for Fiber that provides Cross-site request forgery protection by passing a csrf token via cookies. This cookie value will be used to compare against the client csrf token on requests, other than those defined as "safe" by RFC9110#section-9.2.1 GET, HEAD, OPTIONS, or TRACE. When the csrf token is invalid, this middleware will return the fiber.ErrForbidden error.

CSRF Tokens are generated on GET requests. You can retrieve the CSRF token with c.Locals(contextKey), where contextKey is the string you set in the config (see Custom Config below).

When no csrf_ cookie is set, or the token has expired, a new token will be generated and csrf_ cookie set.

:::note This middleware uses our Storage package to support various databases through a single interface. The default configuration for this middleware saves data to memory, see the examples below for other databases. :::

Security Considerations

This middleware is designed to protect against CSRF attacks. It does not protect against other attack vectors, such as XSS, and should be used in combination with other security measures.

:::warning Never use 'safe' methods to mutate data. For example, never use a GET request to delete a resource. This middleware will not protect against CSRF attacks on 'safe' methods. :::

In the default configuration, the middleware will generate and store tokens using the fiber.Storage interface. These tokens are not associated with a user session, and, therefore, a Double Submit Cookie pattern is used to validate the token. This means that the token is stored in a cookie and also sent as a header on requests. The middleware will compare the cookie value with the header value to validate the token. This is a secure method of validating the token, as cookies are not accessible to JavaScript and, therefore, cannot be read by an attacker.

:::warning When using this method, it is important that you set the CookieSameSite option to Lax or Strict and that the Extractor is not CsrfFromCookie, and KeyLookup is not cookie:<name>. :::

The Synchronizer Token Pattern (Session)

When using this middleware with a user session, the middleware can be configured to store the token in the session. This method is recommended when using a user session as it is generally more secure than the Double Submit Cookie Pattern.

:::warning When using this method, pre-sessions are required and will be created if a session is not already present. This means that the middleware will create a session for every safe request, even if the request does not require a session. Therefore it is required that the existence of a session is not used to indicate that a user is logged in or authenticated, and that a session value is used to indicate this instead. :::

Defense In Depth

When using this middleware, it is recommended that you serve your pages over HTTPS, that the CookieSecure option is set to true, and that the CookieSameSite option is set to Lax or Strict. This will ensure that the cookie is only sent over HTTPS and that it is not sent on requests from external sites.

Referer Checking

For HTTPS requests, this middleware performs strict referer checking. This means that even if a subdomain can set or modify cookies on your domain, it cant force a user to post to your application since that request wont come from your own exact domain.

Token Lifecycle

Tokens are valid until they expire, or until they are deleted. By default, tokens are valid for 1 hour and each subsequent request will extend the expiration by 1 hour. This means that if a user makes a request every hour, the token will never expire. If a user makes a request after the token has expired, then a new token will be generated and the csrf_ cookie will be set again. This means that the token will only expire if the user does not make a request for the duration of the expiration time.

Token Reuse

By default tokens may be used multiple times. This means that the token will not be deleted after it has been used. If you would like to delete the token after it has been used, then you can set the SingleUseToken option to true. This will delete the token after it has been used, and a new token will be generated on the next request.

:::note Using SingleUseToken comes with usability tradeoffs, and therefore is not enabled by default. It can interfere with the user experience if the user has multiple tabs open, or if the user uses the back button. :::

Deleting Tokens

When the authorization status changes, the CSRF token should be deleted and a new one generated. This can be done by calling handler.DeleteToken(c). This will remove the token found in the request context from the storage and set the csrf_ cookie to an empty value. The next 'safe' request will generate a new token and set the cookie again.

if handler, ok := app.AcquireCtx(ctx).Locals(ConfigDefault.HandlerContextKey).(*CSRFHandler); ok {
	if err := handler.DeleteToken(app.AcquireCtx(ctx)); err != nil {
		// handle error
	}
}

:::note If you are using this middleware with the fiber session middleware, then you can simply call session.Destroy(), session.Regenerate(), or session.Reset() to delete session and the token stored therein. :::

BREACH

It is important to note that the token is sent as a header on every request, and if you include the token in a page that is vulnerable to BREACH, then an attacker may be able to extract the token. To mitigate this, you should take steps such as ensuring that your pages are served over HTTPS, that HTTP compression is disabled, and rate limiting requests.

Signatures

func New(config ...Config) fiber.Handler

Examples

Import the middleware package that is part of the Fiber web framework

import (
    "github.com/gofiber/fiber/v2"
    "github.com/gofiber/fiber/v2/middleware/csrf"
)

After you initiate your Fiber app, you can use the following possibilities:

// Initialize default config
app.Use(csrf.New())

// Or extend your config for customization
app.Use(csrf.New(csrf.Config{
    KeyLookup:      "header:X-Csrf-Token",
    CookieName:     "csrf_",
	CookieSameSite: "Lax",
    Expiration:     1 * time.Hour,
    KeyGenerator:   utils.UUIDv4,
    Extractor:      func(c *fiber.Ctx) (string, error) { ... },
}))

:::note KeyLookup will be ignored if Extractor is explicitly set. :::

It's recommended to use this middleware with fiber/middleware/session to store the CSRF token in the session. This is generally more secure than the default configuration.

Config

Config

Property Type Description Default
Next func(*fiber.Ctx) bool Next defines a function to skip this middleware when returned true. nil
KeyLookup string KeyLookup is a string in the form of "<source>:<key>" that is used to create an Extractor that extracts the token from the request. Possible values: "header:<name>", "query:<name>", "param:<name>", "form:<name>", "cookie:<name>". Ignored if an Extractor is explicitly set. "header:X-CSRF-Token"
CookieName string Name of the csrf cookie. This cookie will store the csrf key. "csrf_"
CookieDomain string Domain of the CSRF cookie. ""
CookiePath string Path of the CSRF cookie. ""
CookieSecure bool Indicates if the CSRF cookie is secure. false
CookieHTTPOnly bool Indicates if the CSRF cookie is HTTP-only. false
CookieSameSite string Value of SameSite cookie. "Lax"
CookieSessionOnly bool Decides whether the cookie should last for only the browser session. Ignores Expiration if set to true. false
Expiration time.Duration Expiration is the duration before the CSRF token will expire. 1 * time.Hour
SingleUseToken bool SingleUseToken indicates if the CSRF token be destroyed and a new one generated on each use. (See TokenLifecycle) false
Storage fiber.Storage Store is used to store the state of the middleware. nil
Session *session.Store Session is used to store the state of the middleware. Overrides Storage if set. nil
SessionKey string SessionKey is the key used to store the token in the session. "fiber.csrf.token"
ContextKey string Context key to store the generated CSRF token into the context. If left empty, the token will not be stored in the context. ""
KeyGenerator func() string KeyGenerator creates a new CSRF token. utils.UUID
CookieExpires time.Duration (Deprecated) Deprecated: Please use Expiration. 0
Cookie *fiber.Cookie (Deprecated) Deprecated: Please use Cookie* related fields. nil
TokenLookup string (Deprecated) Deprecated: Please use KeyLookup. ""
ErrorHandler fiber.ErrorHandler ErrorHandler is executed when an error is returned from fiber.Handler. DefaultErrorHandler
Extractor func(*fiber.Ctx) (string, error) Extractor returns the CSRF token. If set, this will be used in place of an Extractor based on KeyLookup. Extractor based on KeyLookup
HandlerContextKey string HandlerContextKey is used to store the CSRF Handler into context. "fiber.csrf.handler"

Default Config

var ConfigDefault = Config{
	KeyLookup:         "header:" + HeaderName,
	CookieName:        "csrf_",
	CookieSameSite:    "Lax",
	Expiration:        1 * time.Hour,
	KeyGenerator:      utils.UUIDv4,
	ErrorHandler:      defaultErrorHandler,
	Extractor:         CsrfFromHeader(HeaderName),
	SessionKey:        "fiber.csrf.token",
	HandlerContextKey: "fiber.csrf.handler",
}
var ConfigDefault = Config{
	KeyLookup:         "header:" + HeaderName,
	CookieName:        "csrf_",
	CookieSameSite:    "Lax",
	CookieSessionOnly: true,
	CookieHTTPOnly:    true,
	Expiration:        1 * time.Hour,
	KeyGenerator:      utils.UUIDv4,
	ErrorHandler:      defaultErrorHandler,
	Extractor:         CsrfFromHeader(HeaderName),
	Session:           session.Store,
	SessionKey:        "fiber.csrf.token",
	HandlerContextKey: "fiber.csrf.handler",
}

Constants

const (
    HeaderName = "X-Csrf-Token"
)

Custom Storage/Database

You can use any storage from our storage package.

storage := sqlite3.New() // From github.com/gofiber/storage/sqlite3
app.Use(csrf.New(csrf.Config{
	Storage: storage,
}))