SECURITY: store hashed session tokens

This commit is contained in:
Simon Martens
2025-05-29 03:20:35 +02:00
parent e0bb939764
commit 0d0918fb5d
4 changed files with 19 additions and 7 deletions

View File

@@ -135,13 +135,13 @@ func (p *LoginPage) POST(engine *templating.Engine, app core.App) HandleFunc {
return Unauthorized(engine, e, fmt.Errorf("Ihr Benutzerkonto ist deaktiviert. Bitte kontaktieren Sie den Administrator."), data) return Unauthorized(engine, e, fmt.Errorf("Ihr Benutzerkonto ist deaktiviert. Bitte kontaktieren Sie den Administrator."), data)
} }
duration := time.Minute * 60 duration := time.Hour * 2
if formdata.Persistent == "on" { if formdata.Persistent == "on" {
duration = time.Hour * 24 * 90 duration = time.Hour * 24 * 90
} }
token, err := dbmodels.CreateSessionToken(app, record.Id, e.RealIP(), e.Request.UserAgent(), formdata.Persistent == "on", duration) token, err := dbmodels.CreateSessionToken(app, record.Id, e.RealIP(), e.Request.UserAgent(), formdata.Persistent == "on", duration)
if err != nil { if err != nil || token == nil || token.SessionTokenClear == "" {
return engine.Response500(e, err, data) return engine.Response500(e, err, data)
} }
@@ -150,7 +150,7 @@ func (p *LoginPage) POST(engine *templating.Engine, app core.App) HandleFunc {
Name: dbmodels.SESSION_COOKIE_NAME, Name: dbmodels.SESSION_COOKIE_NAME,
Path: "/", Path: "/",
MaxAge: int(duration.Seconds()), MaxAge: int(duration.Seconds()),
Value: token.Token(), Value: token.SessionTokenClear,
SameSite: http.SameSiteLaxMode, SameSite: http.SameSiteLaxMode,
HttpOnly: true, HttpOnly: true,
Secure: true, Secure: true,
@@ -159,7 +159,7 @@ func (p *LoginPage) POST(engine *templating.Engine, app core.App) HandleFunc {
e.SetCookie(&http.Cookie{ e.SetCookie(&http.Cookie{
Name: dbmodels.SESSION_COOKIE_NAME, Name: dbmodels.SESSION_COOKIE_NAME,
Path: "/", Path: "/",
Value: token.Token(), Value: token.SessionTokenClear,
SameSite: http.SameSiteLaxMode, SameSite: http.SameSiteLaxMode,
HttpOnly: true, HttpOnly: true,
Secure: true, Secure: true,

View File

@@ -2,7 +2,9 @@ package dbmodels
import ( import (
"crypto/rand" "crypto/rand"
"crypto/sha256"
"encoding/base64" "encoding/base64"
"encoding/hex"
"fmt" "fmt"
"time" "time"
@@ -14,6 +16,13 @@ const (
secureTokenByteLength = 64 secureTokenByteLength = 64
) )
func HashStringSHA256(data string) string {
hasher := sha256.New()
hasher.Write([]byte(data))
hashedBytes := hasher.Sum(nil)
return hex.EncodeToString(hashedBytes)
}
func generateSecureRandomToken(length int) (string, error) { func generateSecureRandomToken(length int) (string, error) {
if length <= 0 { if length <= 0 {
length = secureTokenByteLength length = secureTokenByteLength
@@ -55,7 +64,8 @@ func CreateSessionToken(
session := NewSession(record) session := NewSession(record)
// Set required fields with hashed tokens // Set required fields with hashed tokens
session.SetToken(sessionTokenClear) session.SessionTokenClear = sessionTokenClear
session.SetToken(HashStringSHA256(sessionTokenClear))
session.SetCSRF(csrfTokenClear) session.SetCSRF(csrfTokenClear)
session.SetUser(userID) session.SetUser(userID)
@@ -67,7 +77,7 @@ func CreateSessionToken(
session.SetLastAccess(types.NowDateTime()) session.SetLastAccess(types.NowDateTime())
session.SetUserAgent(userAgent) session.SetUserAgent(userAgent)
session.SetIP(ipAddress) session.SetIP(ipAddress)
session.SetStatus(TOKEN_STATUS_VALUES[0]) // Active session.SetStatus(TOKEN_STATUS_VALUES[0])
if errSave := app.Save(session); errSave != nil { if errSave := app.Save(session); errSave != nil {
app.Logger().Error("Failed to save session token record", "error", errSave, "userID", userID) app.Logger().Error("Failed to save session token record", "error", errSave, "userID", userID)

View File

@@ -26,6 +26,7 @@ func (s *FixedSession) IsExpired() bool {
var _ core.RecordProxy = (*Place)(nil) var _ core.RecordProxy = (*Place)(nil)
type Session struct { type Session struct {
SessionTokenClear string `json:"-"`
core.BaseRecordProxy core.BaseRecordProxy
} }

View File

@@ -32,7 +32,8 @@ func Authenticated(app core.App) func(*core.RequestEvent) error {
user, session, loaded := SESSION_CACHE.Get(cookie.Value) user, session, loaded := SESSION_CACHE.Get(cookie.Value)
if !loaded { if !loaded {
record, err := app.FindFirstRecordByData(dbmodels.SESSIONS_TABLE, dbmodels.SESSIONS_TOKEN_FIELD, cookie.Value) hashedsession := dbmodels.HashStringSHA256(cookie.Value)
record, err := app.FindFirstRecordByData(dbmodels.SESSIONS_TABLE, dbmodels.SESSIONS_TOKEN_FIELD, hashedsession)
if err != nil { if err != nil {
e.SetCookie(deact_cookie) e.SetCookie(deact_cookie)
e.Response.Header().Set("Clear-Site-Data", "\"cookies\"") e.Response.Header().Set("Clear-Site-Data", "\"cookies\"")