mirror of https://github.com/gofiber/fiber.git
Merge pull request from GHSA-94w9-97p3-p368
* feat: improved csrf with session support * fix: double submit cookie * feat: add warning cookie extractor without session * feat: add warning CsrfFromCookie SameSite * fix: use byes.Equal instead * fix: Overriden CookieName KeyLookup cookie:<name> * feat: Create helpers.go * feat: use compareTokens (constant time compare) * feat: validate cookie to prevent token injection * refactor: clean up csrf.go * docs: update comment about Double Submit Cookie * docs: update docs for CSRF changes * feat: add DeleteToken * refactor: no else * test: add more tests * refactor: re-order tests * docs: update safe methods RCF add note * test: add CSRF_Cookie_Injection_Exploit * feat: add SingleUseToken config * test: check for new token * docs: use warning * fix: always register type Token * feat: use UUIDv4 * test: swap in UUIDv4 here too * fix: raw token injection * fix: merege error * feat: Sentinel errors * chore: rename test * fix: url parse * test: add path to referer * test: add expiration tests * docs: add cookie prefix note * docs: fix typo * docs: add warning for refer checks * test: add referer edge cases And call ctx.Request.Reset() and ctx.Response.Reset() before re-using ctx.pull/2679/head
parent
d736d3a644
commit
8c3916dbf4
|
@ -42,10 +42,20 @@ When using this method, pre-sessions are required and will be created if a sessi
|
|||
|
||||
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.
|
||||
|
||||
:::note
|
||||
Cookie prefixes __Host- and __Secure- can be used to further secure the cookie. However, these prefixes are not supported by all browsers and there are some other limitations. See [MDN#Set-Cookie#cookie_prefixes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#cookie_prefixes) for more information.
|
||||
|
||||
To use these prefixes, set the `CookieName` option to `__Host-csrf_` or `__Secure-csrf_`.
|
||||
:::
|
||||
|
||||
### 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 can’t force a user to post to your application since that request won’t come from your own exact domain.
|
||||
|
||||
:::warning
|
||||
Referer checking is required for https requests protected by CSRF. All modern browsers will automatically include the Referer header in requests, including those made with the JS Fetch API. However, if you are using this middleware with a custom client you must ensure that the client sends a valid Referer header.
|
||||
:::
|
||||
|
||||
### 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.
|
||||
|
|
|
@ -2,6 +2,7 @@ package csrf
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
|
@ -63,10 +64,10 @@ func New(config ...Config) fiber.Handler {
|
|||
cookieToken := c.Cookies(cfg.CookieName)
|
||||
|
||||
if cookieToken != "" {
|
||||
rawToken := getTokenFromStorage(c, cookieToken, cfg, sessionManager, storageManager)
|
||||
raw := getRawFromStorage(c, cookieToken, cfg, sessionManager, storageManager)
|
||||
|
||||
if rawToken != nil {
|
||||
token = string(rawToken)
|
||||
if raw != nil {
|
||||
token = cookieToken // Token is valid, safe to set it
|
||||
}
|
||||
}
|
||||
default:
|
||||
|
@ -92,13 +93,13 @@ func New(config ...Config) fiber.Handler {
|
|||
// If not using CsrfFromCookie extractor, check that the token matches the cookie
|
||||
// This is to prevent CSRF attacks by using a Double Submit Cookie method
|
||||
// Useful when we do not have access to the users Session
|
||||
if !isCsrfFromCookie(cfg.Extractor) && extractedToken != c.Cookies(cfg.CookieName) {
|
||||
if !isCsrfFromCookie(cfg.Extractor) && !compareStrings(extractedToken, c.Cookies(cfg.CookieName)) {
|
||||
return cfg.ErrorHandler(c, ErrTokenInvalid)
|
||||
}
|
||||
|
||||
rawToken := getTokenFromStorage(c, extractedToken, cfg, sessionManager, storageManager)
|
||||
raw := getRawFromStorage(c, extractedToken, cfg, sessionManager, storageManager)
|
||||
|
||||
if rawToken == nil {
|
||||
if raw == nil {
|
||||
// If token is not in storage, expire the cookie
|
||||
expireCSRFCookie(c, cfg)
|
||||
// and return an error
|
||||
|
@ -108,7 +109,7 @@ func New(config ...Config) fiber.Handler {
|
|||
// If token is single use, delete it from storage
|
||||
deleteTokenFromStorage(c, extractedToken, cfg, sessionManager, storageManager)
|
||||
} else {
|
||||
token = string(rawToken)
|
||||
token = extractedToken // Token is valid, safe to set it
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,9 +138,9 @@ func New(config ...Config) fiber.Handler {
|
|||
}
|
||||
}
|
||||
|
||||
// getTokenFromStorage returns the raw token from the storage
|
||||
// getRawFromStorage returns the raw value from the storage for the given token
|
||||
// returns nil if the token does not exist, is expired or is invalid
|
||||
func getTokenFromStorage(c *fiber.Ctx, token string, cfg Config, sessionManager *sessionManager, storageManager *storageManager) []byte {
|
||||
func getRawFromStorage(c *fiber.Ctx, token string, cfg Config, sessionManager *sessionManager, storageManager *storageManager) []byte {
|
||||
if cfg.Session != nil {
|
||||
return sessionManager.getRaw(c, token, dummyValue)
|
||||
}
|
||||
|
@ -223,8 +224,15 @@ func refererMatchesHost(c *fiber.Ctx) error {
|
|||
if referer == "" {
|
||||
return ErrNoReferer
|
||||
}
|
||||
if referer != c.Protocol()+"://"+c.Hostname() {
|
||||
|
||||
refererURL, err := url.Parse(referer)
|
||||
if err != nil {
|
||||
return ErrBadReferer
|
||||
}
|
||||
|
||||
if refererURL.Scheme+"://"+refererURL.Host != c.Protocol()+"://"+c.Hostname() {
|
||||
return ErrBadReferer
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/session"
|
||||
|
@ -153,6 +154,170 @@ func Test_CSRF_WithSession(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// go test -run Test_CSRF_ExpiredToken
|
||||
func Test_CSRF_ExpiredToken(t *testing.T) {
|
||||
t.Parallel()
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(New(Config{
|
||||
Expiration: 1 * time.Second,
|
||||
}))
|
||||
|
||||
app.Post("/", func(c *fiber.Ctx) error {
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
})
|
||||
|
||||
h := app.Handler()
|
||||
ctx := &fasthttp.RequestCtx{}
|
||||
|
||||
// Generate CSRF token
|
||||
ctx.Request.Header.SetMethod(fiber.MethodGet)
|
||||
h(ctx)
|
||||
token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie))
|
||||
token = strings.Split(strings.Split(token, ";")[0], "=")[1]
|
||||
|
||||
// Use the CSRF token
|
||||
ctx.Request.Reset()
|
||||
ctx.Response.Reset()
|
||||
ctx.Request.Header.SetMethod(fiber.MethodPost)
|
||||
ctx.Request.Header.Set(HeaderName, token)
|
||||
ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token)
|
||||
h(ctx)
|
||||
utils.AssertEqual(t, 200, ctx.Response.StatusCode())
|
||||
|
||||
// Wait for the token to expire
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
// Expired CSRF token
|
||||
ctx.Request.Reset()
|
||||
ctx.Response.Reset()
|
||||
ctx.Request.Header.SetMethod(fiber.MethodPost)
|
||||
ctx.Request.Header.Set(HeaderName, token)
|
||||
ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token)
|
||||
h(ctx)
|
||||
utils.AssertEqual(t, 403, ctx.Response.StatusCode())
|
||||
}
|
||||
|
||||
// go test -run Test_CSRF_ExpiredToken_WithSession
|
||||
func Test_CSRF_ExpiredToken_WithSession(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// session store
|
||||
store := session.New(session.Config{
|
||||
KeyLookup: "cookie:_session",
|
||||
})
|
||||
|
||||
// fiber instance
|
||||
app := fiber.New()
|
||||
|
||||
// fiber context
|
||||
ctx := &fasthttp.RequestCtx{}
|
||||
defer app.ReleaseCtx(app.AcquireCtx(ctx))
|
||||
|
||||
// get session
|
||||
sess, err := store.Get(app.AcquireCtx(ctx))
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, true, sess.Fresh())
|
||||
|
||||
// get session id
|
||||
newSessionIDString := sess.ID()
|
||||
app.AcquireCtx(ctx).Request().Header.SetCookie("_session", newSessionIDString)
|
||||
|
||||
// middleware config
|
||||
config := Config{
|
||||
Session: store,
|
||||
Expiration: 1 * time.Second,
|
||||
}
|
||||
|
||||
// middleware
|
||||
app.Use(New(config))
|
||||
|
||||
app.Post("/", func(c *fiber.Ctx) error {
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
})
|
||||
|
||||
h := app.Handler()
|
||||
|
||||
// Generate CSRF token
|
||||
ctx.Request.Header.SetMethod(fiber.MethodGet)
|
||||
ctx.Request.Header.SetCookie("_session", newSessionIDString)
|
||||
h(ctx)
|
||||
token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie))
|
||||
for _, header := range strings.Split(token, ";") {
|
||||
if strings.Split(strings.TrimSpace(header), "=")[0] == ConfigDefault.CookieName {
|
||||
token = strings.Split(header, "=")[1]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Use the CSRF token
|
||||
ctx.Request.Reset()
|
||||
ctx.Response.Reset()
|
||||
ctx.Request.Header.SetMethod(fiber.MethodPost)
|
||||
ctx.Request.Header.Set(HeaderName, token)
|
||||
ctx.Request.Header.SetCookie("_session", newSessionIDString)
|
||||
ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token)
|
||||
h(ctx)
|
||||
utils.AssertEqual(t, 200, ctx.Response.StatusCode())
|
||||
|
||||
// Wait for the token to expire
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
// Expired CSRF token
|
||||
ctx.Request.Reset()
|
||||
ctx.Response.Reset()
|
||||
ctx.Request.Header.SetMethod(fiber.MethodPost)
|
||||
ctx.Request.Header.Set(HeaderName, token)
|
||||
ctx.Request.Header.SetCookie("_session", newSessionIDString)
|
||||
ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token)
|
||||
h(ctx)
|
||||
utils.AssertEqual(t, 403, ctx.Response.StatusCode())
|
||||
}
|
||||
|
||||
// go test -run Test_CSRF_MultiUseToken
|
||||
func Test_CSRF_MultiUseToken(t *testing.T) {
|
||||
t.Parallel()
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(New(Config{
|
||||
KeyLookup: "header:X-CSRF-Token",
|
||||
}))
|
||||
|
||||
app.Post("/", func(c *fiber.Ctx) error {
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
})
|
||||
|
||||
h := app.Handler()
|
||||
ctx := &fasthttp.RequestCtx{}
|
||||
|
||||
// Invalid CSRF token
|
||||
ctx.Request.Header.SetMethod(fiber.MethodPost)
|
||||
ctx.Request.Header.Set("X-CSRF-Token", "johndoe")
|
||||
h(ctx)
|
||||
utils.AssertEqual(t, 403, ctx.Response.StatusCode())
|
||||
|
||||
// Generate CSRF token
|
||||
ctx.Request.Reset()
|
||||
ctx.Response.Reset()
|
||||
ctx.Request.Header.SetMethod(fiber.MethodGet)
|
||||
h(ctx)
|
||||
token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie))
|
||||
token = strings.Split(strings.Split(token, ";")[0], "=")[1]
|
||||
|
||||
ctx.Request.Reset()
|
||||
ctx.Response.Reset()
|
||||
ctx.Request.Header.SetMethod(fiber.MethodPost)
|
||||
ctx.Request.Header.Set("X-CSRF-Token", token)
|
||||
ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token)
|
||||
h(ctx)
|
||||
newToken := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie))
|
||||
newToken = strings.Split(strings.Split(newToken, ";")[0], "=")[1]
|
||||
utils.AssertEqual(t, 200, ctx.Response.StatusCode())
|
||||
|
||||
// Check if the token is not a dummy value
|
||||
utils.AssertEqual(t, token, newToken)
|
||||
}
|
||||
|
||||
// go test -run Test_CSRF_SingleUseToken
|
||||
func Test_CSRF_SingleUseToken(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
@ -260,6 +425,8 @@ func Test_CSRF_From_Form(t *testing.T) {
|
|||
token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie))
|
||||
token = strings.Split(strings.Split(token, ";")[0], "=")[1]
|
||||
|
||||
ctx.Request.Reset()
|
||||
ctx.Response.Reset()
|
||||
ctx.Request.Header.SetMethod(fiber.MethodPost)
|
||||
ctx.Request.Header.Set(fiber.HeaderContentType, fiber.MIMEApplicationForm)
|
||||
ctx.Request.SetBodyString("_csrf=" + token)
|
||||
|
@ -393,7 +560,7 @@ func Test_CSRF_From_Custom(t *testing.T) {
|
|||
selectors := strings.Split(body, "=")
|
||||
|
||||
if len(selectors) != 2 || selectors[1] == "" {
|
||||
return "", errMissingParam
|
||||
return "", ErrMissingParam
|
||||
}
|
||||
return selectors[1], nil
|
||||
}
|
||||
|
@ -421,6 +588,8 @@ func Test_CSRF_From_Custom(t *testing.T) {
|
|||
token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie))
|
||||
token = strings.Split(strings.Split(token, ";")[0], "=")[1]
|
||||
|
||||
ctx.Request.Reset()
|
||||
ctx.Response.Reset()
|
||||
ctx.Request.Header.SetMethod(fiber.MethodPost)
|
||||
ctx.Request.Header.Set(fiber.HeaderContentType, fiber.MIMETextPlain)
|
||||
ctx.Request.SetBodyString("_csrf=" + token)
|
||||
|
@ -447,17 +616,67 @@ func Test_CSRF_Referer(t *testing.T) {
|
|||
token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie))
|
||||
token = strings.Split(strings.Split(token, ";")[0], "=")[1]
|
||||
|
||||
// Test Correct Referer
|
||||
// Test Correct Referer with port
|
||||
ctx.Request.Reset()
|
||||
ctx.Response.Reset()
|
||||
ctx.Request.Header.SetMethod(fiber.MethodPost)
|
||||
ctx.Request.URI().SetScheme("https")
|
||||
ctx.Request.URI().SetHost("example.com:8443")
|
||||
ctx.Request.Header.SetProtocol("https")
|
||||
ctx.Request.Header.SetHost("example.com:8443")
|
||||
ctx.Request.Header.Set(fiber.HeaderReferer, ctx.Request.URI().String())
|
||||
ctx.Request.Header.Set(HeaderName, token)
|
||||
ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token)
|
||||
h(ctx)
|
||||
utils.AssertEqual(t, 200, ctx.Response.StatusCode())
|
||||
|
||||
// Test Correct Referer with ReverseProxy
|
||||
ctx.Request.Reset()
|
||||
ctx.Response.Reset()
|
||||
ctx.Request.Header.SetMethod(fiber.MethodPost)
|
||||
ctx.Request.URI().SetScheme("https")
|
||||
ctx.Request.URI().SetHost("10.0.1.42.com:8443")
|
||||
ctx.Request.Header.SetProtocol("https")
|
||||
ctx.Request.Header.SetHost("10.0.1.42:8443")
|
||||
ctx.Request.Header.Set(fiber.HeaderXForwardedProto, "https")
|
||||
ctx.Request.Header.Set(fiber.HeaderXForwardedHost, "example.com")
|
||||
ctx.Request.Header.Set(fiber.HeaderXForwardedFor, `192.0.2.43, "[2001:db8:cafe::17]"`)
|
||||
ctx.Request.Header.Set(fiber.HeaderReferer, "https://example.com")
|
||||
ctx.Request.Header.Set(HeaderName, token)
|
||||
ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token)
|
||||
h(ctx)
|
||||
utils.AssertEqual(t, 200, ctx.Response.StatusCode())
|
||||
|
||||
// Test Correct Referer with ReverseProxy Missing X-Forwarded-* Headers
|
||||
ctx.Request.Reset()
|
||||
ctx.Response.Reset()
|
||||
ctx.Request.Header.SetMethod(fiber.MethodPost)
|
||||
ctx.Request.URI().SetScheme("https")
|
||||
ctx.Request.URI().SetHost("10.0.1.42:8443")
|
||||
ctx.Request.Header.SetProtocol("https")
|
||||
ctx.Request.Header.SetHost("10.0.1.42:8443")
|
||||
ctx.Request.Header.Set(fiber.HeaderXUrlScheme, "https") // We need to set this header to make sure c.Protocol() returns https
|
||||
ctx.Request.Header.Set(fiber.HeaderReferer, "https://example.com")
|
||||
ctx.Request.Header.Set(HeaderName, token)
|
||||
ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token)
|
||||
h(ctx)
|
||||
utils.AssertEqual(t, 403, ctx.Response.StatusCode())
|
||||
|
||||
// Test Correct Referer with path
|
||||
ctx.Request.Reset()
|
||||
ctx.Response.Reset()
|
||||
ctx.Request.Header.SetMethod(fiber.MethodPost)
|
||||
ctx.Request.Header.Set(fiber.HeaderXForwardedProto, "https")
|
||||
ctx.Request.Header.Set(fiber.HeaderXForwardedHost, "example.com")
|
||||
ctx.Request.Header.Set(fiber.HeaderReferer, "https://example.com/action/items?gogogo=true")
|
||||
ctx.Request.Header.Set(HeaderName, token)
|
||||
ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token)
|
||||
h(ctx)
|
||||
utils.AssertEqual(t, 200, ctx.Response.StatusCode())
|
||||
|
||||
// Test Wrong Referer
|
||||
ctx.Request.Reset()
|
||||
ctx.Response.Reset()
|
||||
ctx.Request.Header.SetMethod(fiber.MethodPost)
|
||||
ctx.Request.Header.Set(fiber.HeaderXForwardedProto, "https")
|
||||
ctx.Request.Header.Set(fiber.HeaderXForwardedHost, "example.com")
|
||||
|
@ -490,7 +709,6 @@ func Test_CSRF_DeleteToken(t *testing.T) {
|
|||
token = strings.Split(strings.Split(token, ";")[0], "=")[1]
|
||||
|
||||
// Delete the CSRF token
|
||||
ctx.Request.Header.SetMethod(fiber.MethodGet)
|
||||
ctx.Request.Reset()
|
||||
ctx.Response.Reset()
|
||||
ctx.Request.Header.SetMethod(fiber.MethodPost)
|
||||
|
@ -503,7 +721,6 @@ func Test_CSRF_DeleteToken(t *testing.T) {
|
|||
}
|
||||
h(ctx)
|
||||
|
||||
ctx.Request.Header.SetMethod(fiber.MethodGet)
|
||||
ctx.Request.Reset()
|
||||
ctx.Response.Reset()
|
||||
ctx.Request.Header.SetMethod(fiber.MethodPost)
|
||||
|
@ -559,7 +776,6 @@ func Test_CSRF_DeleteToken_WithSession(t *testing.T) {
|
|||
token = strings.Split(strings.Split(token, ";")[0], "=")[1]
|
||||
|
||||
// Delete the CSRF token
|
||||
ctx.Request.Header.SetMethod(fiber.MethodGet)
|
||||
ctx.Request.Reset()
|
||||
ctx.Response.Reset()
|
||||
ctx.Request.Header.SetMethod(fiber.MethodPost)
|
||||
|
@ -619,7 +835,7 @@ func Test_CSRF_ErrorHandler_EmptyToken(t *testing.T) {
|
|||
app := fiber.New()
|
||||
|
||||
errHandler := func(ctx *fiber.Ctx, err error) error {
|
||||
utils.AssertEqual(t, errMissingHeader, err)
|
||||
utils.AssertEqual(t, ErrMissingHeader, err)
|
||||
return ctx.Status(419).Send([]byte("empty CSRF token"))
|
||||
}
|
||||
|
||||
|
@ -671,6 +887,8 @@ func Test_CSRF_ErrorHandler_MissingReferer(t *testing.T) {
|
|||
token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie))
|
||||
token = strings.Split(strings.Split(token, ";")[0], "=")[1]
|
||||
|
||||
ctx.Request.Reset()
|
||||
ctx.Response.Reset()
|
||||
ctx.Request.Header.SetMethod(fiber.MethodPost)
|
||||
ctx.Request.Header.Set(fiber.HeaderXForwardedProto, "https")
|
||||
ctx.Request.Header.Set(fiber.HeaderXForwardedHost, "example.com")
|
||||
|
|
|
@ -7,11 +7,11 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
errMissingHeader = errors.New("missing csrf token in header")
|
||||
errMissingQuery = errors.New("missing csrf token in query")
|
||||
errMissingParam = errors.New("missing csrf token in param")
|
||||
errMissingForm = errors.New("missing csrf token in form")
|
||||
errMissingCookie = errors.New("missing csrf token in cookie")
|
||||
ErrMissingHeader = errors.New("missing csrf token in header")
|
||||
ErrMissingQuery = errors.New("missing csrf token in query")
|
||||
ErrMissingParam = errors.New("missing csrf token in param")
|
||||
ErrMissingForm = errors.New("missing csrf token in form")
|
||||
ErrMissingCookie = errors.New("missing csrf token in cookie")
|
||||
)
|
||||
|
||||
// csrfFromParam returns a function that extracts token from the url param string.
|
||||
|
@ -19,7 +19,7 @@ func CsrfFromParam(param string) func(c *fiber.Ctx) (string, error) {
|
|||
return func(c *fiber.Ctx) (string, error) {
|
||||
token := c.Params(param)
|
||||
if token == "" {
|
||||
return "", errMissingParam
|
||||
return "", ErrMissingParam
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ func CsrfFromForm(param string) func(c *fiber.Ctx) (string, error) {
|
|||
return func(c *fiber.Ctx) (string, error) {
|
||||
token := c.FormValue(param)
|
||||
if token == "" {
|
||||
return "", errMissingForm
|
||||
return "", ErrMissingForm
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ func CsrfFromCookie(param string) func(c *fiber.Ctx) (string, error) {
|
|||
return func(c *fiber.Ctx) (string, error) {
|
||||
token := c.Cookies(param)
|
||||
if token == "" {
|
||||
return "", errMissingCookie
|
||||
return "", ErrMissingCookie
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ func CsrfFromHeader(param string) func(c *fiber.Ctx) (string, error) {
|
|||
return func(c *fiber.Ctx) (string, error) {
|
||||
token := c.Get(param)
|
||||
if token == "" {
|
||||
return "", errMissingHeader
|
||||
return "", ErrMissingHeader
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ func CsrfFromQuery(param string) func(c *fiber.Ctx) (string, error) {
|
|||
return func(c *fiber.Ctx) (string, error) {
|
||||
token := c.Query(param)
|
||||
if token == "" {
|
||||
return "", errMissingQuery
|
||||
return "", ErrMissingQuery
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
|
|
@ -7,3 +7,7 @@ import (
|
|||
func compareTokens(a, b []byte) bool {
|
||||
return subtle.ConstantTimeCompare(a, b) == 1
|
||||
}
|
||||
|
||||
func compareStrings(a, b string) bool {
|
||||
return subtle.ConstantTimeCompare([]byte(a), []byte(b)) == 1
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue