security: Implement HIGH priority security improvements
HIGH Priority Security Features: - Path sanitization with filepath.Clean() for all user paths - Path traversal attack prevention in backup/restore operations - Secure config file permissions (0600 instead of 0644) - SHA-256 checksum generation for all backup archives - Checksum verification during restore operations - Comprehensive audit logging for compliance New Security Module (internal/security/): - paths.go: ValidateBackupPath() and ValidateArchivePath() - checksum.go: ChecksumFile(), VerifyChecksum(), LoadAndVerifyChecksum() - audit.go: AuditLogger with structured event tracking Integration Points: - Backup engine: Path validation, checksum generation - Restore engine: Path validation, checksum verification - All backup/restore operations: Audit logging - Configuration saves: Audit logging Security Enhancements: - .dbbackup.conf now created with 0600 permissions (owner-only) - All archive files get .sha256 checksum files - Restore warns if checksum verification fails but continues - Audit events logged for all administrative operations - User tracking via $USER/$USERNAME environment variables Compliance Features: - Audit trail for backups, restores, config changes - Structured logging with timestamps, users, actions, results - Event details include paths, sizes, durations, errors Testing: - All code compiles successfully - Cross-platform build verified - Ready for integration testing
This commit is contained in:
72
internal/security/paths.go
Normal file
72
internal/security/paths.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package security
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CleanPath sanitizes a file path to prevent path traversal attacks
|
||||
func CleanPath(path string) (string, error) {
|
||||
if path == "" {
|
||||
return "", fmt.Errorf("path cannot be empty")
|
||||
}
|
||||
|
||||
// Clean the path (removes .., ., //)
|
||||
cleaned := filepath.Clean(path)
|
||||
|
||||
// Detect path traversal attempts
|
||||
if strings.Contains(cleaned, "..") {
|
||||
return "", fmt.Errorf("path traversal detected: %s", path)
|
||||
}
|
||||
|
||||
return cleaned, nil
|
||||
}
|
||||
|
||||
// ValidateBackupPath ensures backup path is safe
|
||||
func ValidateBackupPath(path string) (string, error) {
|
||||
cleaned, err := CleanPath(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Convert to absolute path
|
||||
absPath, err := filepath.Abs(cleaned)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get absolute path: %w", err)
|
||||
}
|
||||
|
||||
return absPath, nil
|
||||
}
|
||||
|
||||
// ValidateArchivePath validates an archive file path
|
||||
func ValidateArchivePath(path string) (string, error) {
|
||||
cleaned, err := CleanPath(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Must have a valid archive extension
|
||||
ext := strings.ToLower(filepath.Ext(cleaned))
|
||||
validExtensions := []string{".dump", ".sql", ".gz", ".tar"}
|
||||
|
||||
valid := false
|
||||
for _, validExt := range validExtensions {
|
||||
if strings.HasSuffix(cleaned, validExt) {
|
||||
valid = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !valid {
|
||||
return "", fmt.Errorf("invalid archive extension: %s (must be .dump, .sql, .gz, or .tar)", ext)
|
||||
}
|
||||
|
||||
// Convert to absolute path
|
||||
absPath, err := filepath.Abs(cleaned)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get absolute path: %w", err)
|
||||
}
|
||||
|
||||
return absPath, nil
|
||||
}
|
||||
Reference in New Issue
Block a user