package filesystem import ( "fmt" "os" "path/filepath" "runtime" "strings" "sync" ) // PathValidator 路径验证器接口 // 提供统一的路径安全检查,避免重复代码 type PathValidator interface { // Validate 验证路径并返回详细的错误信息 Validate(path string) *ValidationError // IsSafe 快速检查路径是否安全 IsSafe(path string) bool // IsSensitive 检查路径是否为敏感路径 IsSensitive(path string) bool } // ValidationError 验证错误 type ValidationError struct { Path string Reason string IsError bool // true=禁止访问, false=敏感路径 } func (e *ValidationError) Error() string { if e.IsError { return fmt.Sprintf("路径验证失败: %s - %s", e.Path, e.Reason) } return fmt.Sprintf("敏感路径警告: %s - %s", e.Path, e.Reason) } // DefaultPathValidator 默认路径验证器实现 type DefaultPathValidator struct { config *Config } // NewPathValidator 创建新的路径验证器 func NewPathValidator(config *Config) PathValidator { return &DefaultPathValidator{ config: config, } } // Validate 验证路径 func (v *DefaultPathValidator) Validate(path string) *ValidationError { // 清理路径 cleanPath := filepath.Clean(path) // 1. 检查路径遍历攻击 if strings.Contains(cleanPath, PathTraversalPattern) { return &ValidationError{ Path: path, Reason: "检测到路径遍历尝试", IsError: true, } } // 2. 检查符号链接 if !v.config.Security.PathValidation.AllowSymlinks { if fi, err := os.Lstat(path); err == nil && fi.Mode()&os.ModeSymlink != 0 { return &ValidationError{ Path: path, Reason: "不允许访问符号链接", IsError: true, } } } // 3. 检查UNC路径(Windows) if runtime.GOOS == "windows" && !v.config.Security.PathValidation.AllowUNCPaths { if strings.HasPrefix(cleanPath, `\\`) { return &ValidationError{ Path: path, Reason: "不允许访问UNC网络路径", IsError: true, } } } // 4. Windows特定检查 if runtime.GOOS == "windows" && v.config.Security.PathValidation.CheckWindowsSystemPaths { if err := v.checkWindowsSystemPaths(cleanPath); err != nil { return err } } // 5. 检查敏感路径 if v.isSensitivePath(cleanPath) { return &ValidationError{ Path: path, Reason: "访问敏感路径", IsError: false, // 警告而非错误 } } return nil } // IsSafe 快速检查路径是否安全 func (v *DefaultPathValidator) IsSafe(path string) bool { err := v.Validate(path) return err == nil || !err.IsError } // IsSensitive 检查路径是否为敏感路径 func (v *DefaultPathValidator) IsSensitive(path string) bool { cleanPath := filepath.Clean(path) return v.isSensitivePath(cleanPath) } // checkWindowsSystemPaths 检查Windows系统路径 func (v *DefaultPathValidator) checkWindowsSystemPaths(path string) *ValidationError { lowerPath := strings.ToLower(path) // 检查盘符 if len(lowerPath) >= 3 && lowerPath[1] == ':' { driveLetter := lowerPath[0:1] // 检查系统核心目录 forbiddenDirs := []string{ driveLetter + ":\\windows", driveLetter + ":\\system volume information", driveLetter + ":\\boot", } for _, fb := range forbiddenDirs { if strings.HasPrefix(lowerPath, fb) { return &ValidationError{ Path: path, Reason: "禁止访问系统关键目录", IsError: true, } } } // 检查用户配置目录(可能包含敏感信息) forbiddenPaths := []string{ "\\.ssh\\", "\\.gnupg\\", "\\.config\\", "\\appdata\\roaming\\mozilla\\", "\\appdata\\roaming\\google\\chrome\\", "\\appdata\\local\\google\\user data\\", } for _, fp := range forbiddenPaths { if strings.Contains(lowerPath, fp) { return &ValidationError{ Path: path, Reason: "禁止访问敏感配置目录", IsError: true, } } } } return nil } // isSensitivePath 检查是否为敏感路径 func (v *DefaultPathValidator) isSensitivePath(path string) bool { lowerPath := strings.ToLower(filepath.Clean(path)) // 检查配置的敏感路径列表 for _, sp := range v.config.Security.PathValidation.SensitivePaths { if strings.Contains(lowerPath, strings.ToLower(sp)) { return true } } return false } // 默认路径验证器(缓存,避免每次调用重复初始化) var ( defaultValidatorOnce sync.Once defaultValidator PathValidator ) func getDefaultValidator() PathValidator { defaultValidatorOnce.Do(func() { defaultValidator = NewPathValidator(DefaultConfig()) }) return defaultValidator } // isSafePath 兼容函数:保持向后兼容 func isSafePath(path string) bool { return getDefaultValidator().IsSafe(path) } // isSensitivePath 兼容函数:保持向后兼容 func isSensitivePath(path string) bool { return getDefaultValidator().IsSensitive(path) }