chore: implement Phase 1 and 2 security remediations
Some checks failed
Automated Container Build / build-and-push (push) Has been cancelled
Some checks failed
Automated Container Build / build-and-push (push) Has been cancelled
This commit is contained in:
parent
82731e93b1
commit
701766b611
14 changed files with 213 additions and 55 deletions
|
|
@ -1,7 +1,9 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"mime"
|
||||
"net/http"
|
||||
|
|
@ -22,12 +24,13 @@ type WebDAVHandler struct {
|
|||
Handler *webdav.Handler
|
||||
DB *database.DB
|
||||
Config *config.Config
|
||||
Guard *middleware.BruteForceGuard
|
||||
|
||||
authCache map[string]time.Time
|
||||
cacheMu sync.RWMutex
|
||||
}
|
||||
|
||||
func NewWebDAVHandler(db *database.DB, cfg *config.Config) *WebDAVHandler {
|
||||
func NewWebDAVHandler(db *database.DB, cfg *config.Config, guard *middleware.BruteForceGuard) *WebDAVHandler {
|
||||
fs := webdav.Dir(cfg.StorageDir)
|
||||
|
||||
// Create a custom locking system (in-memory for now, could be DB backed)
|
||||
|
|
@ -48,6 +51,7 @@ func NewWebDAVHandler(db *database.DB, cfg *config.Config) *WebDAVHandler {
|
|||
Handler: h,
|
||||
DB: db,
|
||||
Config: cfg,
|
||||
Guard: guard,
|
||||
authCache: make(map[string]time.Time),
|
||||
}
|
||||
}
|
||||
|
|
@ -70,7 +74,8 @@ func (h *WebDAVHandler) Handle(c *fiber.Ctx) error {
|
|||
}
|
||||
|
||||
if hasBasicAuth {
|
||||
cacheKey := user + ":" + pass
|
||||
hasher := sha256.Sum256([]byte(user + ":" + pass))
|
||||
cacheKey := hex.EncodeToString(hasher[:])
|
||||
|
||||
h.cacheMu.RLock()
|
||||
expireTime, ok := h.authCache[cacheKey]
|
||||
|
|
@ -81,20 +86,26 @@ func (h *WebDAVHandler) Handle(c *fiber.Ctx) error {
|
|||
var storedHash string
|
||||
err := h.DB.QueryRow("SELECT password_hash FROM users WHERE username = ?", user).Scan(&storedHash)
|
||||
if err != nil || !verifyPassword(pass, storedHash) {
|
||||
h.Guard.RecordFailure(c.IP())
|
||||
c.Set("WWW-Authenticate", `Basic realm="Drive WebDAV"`)
|
||||
return c.SendStatus(fiber.StatusUnauthorized)
|
||||
}
|
||||
h.Guard.RecordSuccess(c.IP())
|
||||
|
||||
// Cache successful auth for 5 minutes
|
||||
h.cacheMu.Lock()
|
||||
h.authCache[cacheKey] = time.Now().Add(5 * time.Minute)
|
||||
|
||||
// Simple cache cleanup
|
||||
for k, v := range h.authCache {
|
||||
if time.Now().After(v) {
|
||||
delete(h.authCache, k)
|
||||
// Bounded cache to prevent DoS
|
||||
if len(h.authCache) >= 1000 {
|
||||
now := time.Now()
|
||||
for k, v := range h.authCache {
|
||||
if now.After(v) {
|
||||
delete(h.authCache, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(h.authCache) < 1000 {
|
||||
h.authCache[cacheKey] = time.Now().Add(5 * time.Minute)
|
||||
}
|
||||
h.cacheMu.Unlock()
|
||||
}
|
||||
} else if c.Locals("userID") == nil {
|
||||
|
|
|
|||
Reference in a new issue