fix: security hardening for middleware, crypto, and backup handlers
- Remove CORS origin reflection (SEC-C1 CRITICAL) - Add Content-Security-Policy header (SEC-H2) - Fix rate limiter memory leak with periodic stale IP cleanup (SEC-H5) - Enforce minimum 32-char ENCRYPTION_KEY (SEC-H4) - Validate backup type against allowlist (SEC-M6) - Fix backup download path traversal with path containment check (SEC-C2 CRITICAL)
This commit is contained in:
+24
-2
@@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/alexei/docker-watcher/internal/store"
|
||||
@@ -69,14 +70,35 @@ func (s *Server) downloadBackup(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
filePath := s.backupEngine.FilePath(backup)
|
||||
if _, err := os.Stat(filePath); err != nil {
|
||||
|
||||
// Validate the resolved path stays within the backup directory to prevent path traversal.
|
||||
absPath, err := filepath.Abs(filePath)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, "failed to resolve backup path")
|
||||
return
|
||||
}
|
||||
absBackupDir, _ := filepath.Abs(s.backupEngine.BackupDir())
|
||||
if !strings.HasPrefix(absPath, absBackupDir+string(filepath.Separator)) {
|
||||
respondError(w, http.StatusForbidden, "access denied")
|
||||
return
|
||||
}
|
||||
|
||||
f, err := os.Open(absPath)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusNotFound, "backup file not found on disk")
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
stat, err := f.Stat()
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, "failed to read backup file")
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
w.Header().Set("Content-Disposition", "attachment; filename=\""+filepath.Base(backup.Filename)+"\"")
|
||||
http.ServeFile(w, r, filePath)
|
||||
http.ServeContent(w, r, filepath.Base(backup.Filename), stat.ModTime(), f)
|
||||
}
|
||||
|
||||
// deleteBackup handles DELETE /api/backups/{id}.
|
||||
|
||||
Reference in New Issue
Block a user