From 9fcaad6b2f09c50e2c62869865c178853eccf777 Mon Sep 17 00:00:00 2001 From: Nazar Kanaev Date: Mon, 4 Jan 2021 14:03:51 +0000 Subject: [PATCH] hmac-based auth --- server/auth.go | 28 +++++++++++++++++++++------- server/handlers.go | 2 +- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/server/auth.go b/server/auth.go index 3d8e5ff..afd710e 100644 --- a/server/auth.go +++ b/server/auth.go @@ -1,30 +1,44 @@ package server import ( - "net/http" + "crypto/hmac" + "crypto/sha256" "crypto/subtle" + "encoding/hex" + "net/http" + "strings" "time" ) - func userIsAuthenticated(req *http.Request, username, password string) bool { cookie, _ := req.Cookie("auth") if cookie == nil { return false } - // TODO: change to something sane - if cookie.Value != username { + parts := strings.Split(cookie.Value, ":") + if len(parts) != 2 || !stringsEqual(parts[0], username) { return false } - return true + return stringsEqual(parts[1], secret(username, password)) } func userAuthenticate(rw http.ResponseWriter, username, password string) { expires := time.Now().Add(time.Hour * 24 * 7) // 1 week - cookie := http.Cookie{Name: "auth", Value: username, Expires: expires} + cookie := http.Cookie{ + Name: "auth", + Value: username + ":" + secret(username, password), + Expires: expires, + } http.SetCookie(rw, &cookie) } -func safeCompare(p1, p2 string) bool { +func stringsEqual(p1, p2 string) bool { return subtle.ConstantTimeCompare([]byte(p1), []byte(p2)) == 1 } + +func secret(msg, key string) string { + mac := hmac.New(sha256.New, []byte(key)) + mac.Write([]byte(msg)) + src := mac.Sum(nil) + return hex.EncodeToString(src) +} diff --git a/server/handlers.go b/server/handlers.go index a67bf8c..2b18178 100644 --- a/server/handlers.go +++ b/server/handlers.go @@ -95,7 +95,7 @@ func IndexHandler(rw http.ResponseWriter, req *http.Request) { if req.Method == "POST" { username := req.FormValue("username") password := req.FormValue("password") - if safeCompare(username, h.Username) && safeCompare(password, h.Password) { + if stringsEqual(username, h.Username) && stringsEqual(password, h.Password) { userAuthenticate(rw, username, password) http.Redirect(rw, req, req.URL.Path, http.StatusFound) return