diff options
author | GrailFinder <wohilas@gmail.com> | 2024-05-05 08:57:23 +0300 |
---|---|---|
committer | GrailFinder <wohilas@gmail.com> | 2024-05-05 08:57:23 +0300 |
commit | ff86222fc9ab85fb4c5c5e8a063083595b323761 (patch) | |
tree | 01dbec5503bfabc21af93acdbfe3d1000e2386a0 /internal | |
parent | 8d66ec58e2256412a2fd50ad9e651c09af1ea8cc (diff) |
Enha: protected cookies
Diffstat (limited to 'internal')
-rw-r--r-- | internal/handlers/auth.go | 23 | ||||
-rw-r--r-- | internal/handlers/middleware.go | 37 | ||||
-rw-r--r-- | internal/models/auth.go | 5 |
3 files changed, 53 insertions, 12 deletions
diff --git a/internal/handlers/auth.go b/internal/handlers/auth.go index 5ec1c80..e7eca50 100644 --- a/internal/handlers/auth.go +++ b/internal/handlers/auth.go @@ -3,6 +3,9 @@ package handlers import ( "apjournal/internal/models" "apjournal/pkg/utils" + "crypto/hmac" + "crypto/sha256" + "encoding/base64" "encoding/json" "html/template" "net/http" @@ -61,6 +64,7 @@ func (h *Handlers) HandleLogin(w http.ResponseWriter, r *http.Request) { } func (h *Handlers) makeCookie(username string, remote string) (*http.Cookie, error) { + // secret // Create a new random session token // sessionToken := xid.New().String() sessionToken := "token" @@ -70,10 +74,18 @@ func (h *Handlers) makeCookie(username string, remote string) (*http.Cookie, err Username: username, Expiry: expiresAt, } - // TODO: write session to db + cookieName := "session_token" + // hmac to protect cookies + hm := hmac.New(sha256.New, []byte(h.cfg.CookieSecret)) + hm.Write([]byte(cookieName)) + hm.Write([]byte(sessionToken)) + signature := hm.Sum(nil) + // b64 enc to avoid non-ascii + cookieValue := base64.URLEncoding.EncodeToString([]byte( + string(signature) + sessionToken)) cookie := &http.Cookie{ - Name: "session_token", - Value: sessionToken, + Name: cookieName, + Value: cookieValue, Secure: true, HttpOnly: true, SameSite: http.SameSiteNoneMode, @@ -86,7 +98,10 @@ func (h *Handlers) makeCookie(username string, remote string) (*http.Cookie, err cookie.Domain = "192.168.0.101" } // set ctx? - // c.Set("username", username) + // set user in session + if err := h.cacheSetSession(sessionToken, session); err != nil { + return nil, err + } return cookie, nil } diff --git a/internal/handlers/middleware.go b/internal/handlers/middleware.go index 28ccdbc..8b871a2 100644 --- a/internal/handlers/middleware.go +++ b/internal/handlers/middleware.go @@ -2,24 +2,51 @@ package handlers import ( "context" + "crypto/hmac" + "crypto/sha256" + "encoding/base64" "errors" "net/http" ) func (h *Handlers) GetSession(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - sessionCookie, err := r.Cookie("session_token") + cookieName := "session_token" + sessionCookie, err := r.Cookie(cookieName) if err != nil { msg := "auth failed; failed to get session token from cookies" h.log.Debug(msg, "error", err) next.ServeHTTP(w, r) return } - sessionToken := "" - if sessionCookie.Value == "" { - sessionToken = sessionCookie.Value + cookieValueB, err := base64.URLEncoding. + DecodeString(sessionCookie.Value) + if err != nil { + msg := "auth failed; failed to decode b64 cookie" + h.log.Debug(msg, "error", err) + next.ServeHTTP(w, r) + return + } + cookieValue := string(cookieValueB) + if len(cookieValue) < sha256.Size { + h.log.Warn("small cookie", "size", len(cookieValue)) + next.ServeHTTP(w, r) + return + } + // Split apart the signature and original cookie value. + signature := cookieValue[:sha256.Size] + sessionToken := cookieValue[sha256.Size:] + //verify signature + mac := hmac.New(sha256.New, []byte(h.cfg.CookieSecret)) + mac.Write([]byte(cookieName)) + mac.Write([]byte(sessionToken)) + expectedSignature := mac.Sum(nil) + if !hmac.Equal([]byte(signature), expectedSignature) { + h.log.Debug("cookie with an invalid sign") + next.ServeHTTP(w, r) + return } - userSession, err := h.cacheGetSession(sessionCookie.Value) + userSession, err := h.cacheGetSession(sessionToken) if err != nil { msg := "auth failed; session does not exists" err = errors.New(msg) diff --git a/internal/models/auth.go b/internal/models/auth.go index 5dadf8a..9964cd5 100644 --- a/internal/models/auth.go +++ b/internal/models/auth.go @@ -6,9 +6,8 @@ import ( // each session contains the username of the user and the time at which it expires type Session struct { - Username string - CurrentRoom string - Expiry time.Time + Username string + Expiry time.Time } // we'll use this method later to determine if the session has expired |