Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix(🩹): error handling in CSRF token storage retrieval #3021

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions middleware/csrf/csrf.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@
ErrRefererNoMatch = errors.New("referer does not match host and is not a trusted origin")
ErrOriginInvalid = errors.New("origin invalid")
ErrOriginNoMatch = errors.New("origin does not match host and is not a trusted origin")
errOriginNotFound = errors.New("origin not supplied or is null") // internal error, will not be returned to the user
dummyValue = []byte{'+'}
ErrNotGetStorage = errors.New("csrf storage not found data")
ErrNotSetStorage = errors.New("csrf storage not set data")
renanbastos93 marked this conversation as resolved.
Show resolved Hide resolved

errOriginNotFound = errors.New("origin not supplied or is null") // internal error, will not be returned to the user
dummyValue = []byte{'+'}
)

// Handler for CSRF middleware
Expand Down Expand Up @@ -102,10 +105,9 @@
switch c.Method() {
case fiber.MethodGet, fiber.MethodHead, fiber.MethodOptions, fiber.MethodTrace:
cookieToken := c.Cookies(cfg.CookieName)

if cookieToken != "" {
raw := getRawFromStorage(c, cookieToken, cfg, sessionManager, storageManager)

// In this case, handling error doesn't make sense because we have validations after the switch.
raw, _ := getRawFromStorage(c, cookieToken, cfg, sessionManager, storageManager)

Check failure on line 110 in middleware/csrf/csrf.go

View workflow job for this annotation

GitHub Actions / lint

Error return value is not checked (errcheck)
renanbastos93 marked this conversation as resolved.
Show resolved Hide resolved
if raw != nil {
token = cookieToken // Token is valid, safe to set it
}
Expand Down Expand Up @@ -148,9 +150,8 @@
return cfg.ErrorHandler(c, ErrTokenInvalid)
}

raw := getRawFromStorage(c, extractedToken, cfg, sessionManager, storageManager)

if raw == nil {
raw, err := getRawFromStorage(c, extractedToken, cfg, sessionManager, storageManager)
if err != nil || raw == nil {
renanbastos93 marked this conversation as resolved.
Show resolved Hide resolved
// If token is not in storage, expire the cookie
expireCSRFCookie(c, cfg)
// and return an error
Expand Down Expand Up @@ -209,7 +210,7 @@

// 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 getRawFromStorage(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) (raw []byte, err error) {

Check failure on line 213 in middleware/csrf/csrf.go

View workflow job for this annotation

GitHub Actions / lint

named return "err" with type "error" found (nonamedreturns)

Check failure on line 213 in middleware/csrf/csrf.go

View workflow job for this annotation

GitHub Actions / lint

named return "raw" with type "[]byte" found (nonamedreturns)
renanbastos93 marked this conversation as resolved.
Show resolved Hide resolved
if cfg.Session != nil {
return sessionManager.getRaw(c, token, dummyValue)
}
Expand All @@ -221,7 +222,7 @@
if cfg.Session != nil {
sessionManager.setRaw(c, token, dummyValue, cfg.Expiration)
} else {
storageManager.setRaw(token, dummyValue, cfg.Expiration)

Check failure on line 225 in middleware/csrf/csrf.go

View workflow job for this annotation

GitHub Actions / lint

unhandled-error: Unhandled error in call to function csrf.storageManager.setRaw (revive)

Check failure on line 225 in middleware/csrf/csrf.go

View workflow job for this annotation

GitHub Actions / lint

Error return value of `storageManager.setRaw` is not checked (errcheck)
}
}

Expand All @@ -229,7 +230,7 @@
if cfg.Session != nil {
sessionManager.delRaw(c)
} else {
storageManager.delRaw(token)

Check failure on line 233 in middleware/csrf/csrf.go

View workflow job for this annotation

GitHub Actions / lint

unhandled-error: Unhandled error in call to function csrf.storageManager.delRaw (revive)

Check failure on line 233 in middleware/csrf/csrf.go

View workflow job for this annotation

GitHub Actions / lint

Error return value of `storageManager.delRaw` is not checked (errcheck)
}
}

Expand Down
18 changes: 10 additions & 8 deletions middleware/csrf/session_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,22 @@
}

// get token from session
func (m *sessionManager) getRaw(c fiber.Ctx, key string, raw []byte) []byte {
func (m *sessionManager) getRaw(c fiber.Ctx, key string, raw []byte) (rawToken []byte, err error) {

Check failure on line 29 in middleware/csrf/session_manager.go

View workflow job for this annotation

GitHub Actions / lint

named return "rawToken" with type "[]byte" found (nonamedreturns)

Check failure on line 29 in middleware/csrf/session_manager.go

View workflow job for this annotation

GitHub Actions / lint

named return "err" with type "error" found (nonamedreturns)
renanbastos93 marked this conversation as resolved.
Show resolved Hide resolved
sess, err := m.session.Get(c)
if err != nil {
return nil
return nil, err

Check warning on line 32 in middleware/csrf/session_manager.go

View check run for this annotation

Codecov / codecov/patch

middleware/csrf/session_manager.go#L32

Added line #L32 was not covered by tests
}

token, ok := sess.Get(m.key).(Token)
if ok {
if token.Expiration.Before(time.Now()) || key != token.Key || !compareTokens(raw, token.Raw) {
return nil
}
return token.Raw
if !ok {
return nil, ErrTokenInvalid
}

if token.Expiration.Before(time.Now()) || key != token.Key || !compareTokens(raw, token.Raw) {
return nil, ErrTokenInvalid
}

return nil
return token.Raw, nil
}

// set token in session
Expand Down
36 changes: 27 additions & 9 deletions middleware/csrf/storage_manager.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package csrf

import (
"fmt"
"sync"
"time"

Expand Down Expand Up @@ -40,31 +41,48 @@
}

// get raw data from storage or memory
func (m *storageManager) getRaw(key string) []byte {
var raw []byte
func (m *storageManager) getRaw(key string) (raw []byte, err error) {

Check failure on line 44 in middleware/csrf/storage_manager.go

View workflow job for this annotation

GitHub Actions / lint

named return "raw" with type "[]byte" found (nonamedreturns)
renanbastos93 marked this conversation as resolved.
Show resolved Hide resolved
if m.storage != nil {
raw, _ = m.storage.Get(key) //nolint:errcheck // TODO: Do not ignore error
raw, err = m.storage.Get(key)
if err != nil {
return nil, fmt.Errorf("%w: %s", ErrNotGetStorage, err.Error())

Check warning on line 48 in middleware/csrf/storage_manager.go

View check run for this annotation

Codecov / codecov/patch

middleware/csrf/storage_manager.go#L46-L48

Added lines #L46 - L48 were not covered by tests
}
} else {
raw, _ = m.memory.Get(key).([]byte) //nolint:errcheck // TODO: Do not ignore error
var ok bool
raw, ok = m.memory.Get(key).([]byte)
if !ok {
return nil, ErrNotGetStorage
}
}
return raw

return raw, nil
}

// set data to storage or memory
func (m *storageManager) setRaw(key string, raw []byte, exp time.Duration) {
func (m *storageManager) setRaw(key string, raw []byte, exp time.Duration) (err error) {
if m.storage != nil {
_ = m.storage.Set(key, raw, exp) //nolint:errcheck // TODO: Do not ignore error
err = m.storage.Set(key, raw, exp)
if err != nil {
return fmt.Errorf("%w: %s", ErrNotSetStorage, err.Error())

Check warning on line 66 in middleware/csrf/storage_manager.go

View check run for this annotation

Codecov / codecov/patch

middleware/csrf/storage_manager.go#L64-L66

Added lines #L64 - L66 were not covered by tests
}
} else {
// the key is crucial in crsf and sometimes a reference to another value which can be reused later(pool/unsafe values concept), so a copy is made here
m.memory.Set(utils.CopyString(key), raw, exp)
}

return nil
}

// delete data from storage or memory
func (m *storageManager) delRaw(key string) {
func (m *storageManager) delRaw(key string) (err error) {
if m.storage != nil {
_ = m.storage.Delete(key) //nolint:errcheck // TODO: Do not ignore error
err = m.storage.Delete(key)
if err != nil {
return fmt.Errorf("%w: %s", ErrNotSetStorage, err.Error())

Check warning on line 81 in middleware/csrf/storage_manager.go

View check run for this annotation

Codecov / codecov/patch

middleware/csrf/storage_manager.go#L79-L81

Added lines #L79 - L81 were not covered by tests
}
} else {
m.memory.Delete(key)
}

return nil
}
Loading