重构:文件系统模块化架构,优化应用启动流程
This commit is contained in:
197
internal/filesystem/path_validator.go
Normal file
197
internal/filesystem/path_validator.go
Normal file
@@ -0,0 +1,197 @@
|
||||
package filesystem
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 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 + ":\\program files",
|
||||
driveLetter + ":\\program files (x86)",
|
||||
driveLetter + ":\\program files (arm)",
|
||||
driveLetter + ":\\programdata",
|
||||
driveLetter + ":\\system volume information",
|
||||
driveLetter + ":\\recovery",
|
||||
driveLetter + ":\\boot",
|
||||
}
|
||||
|
||||
for _, fb := range forbiddenDirs {
|
||||
if strings.HasPrefix(lowerPath, fb) {
|
||||
return &ValidationError{
|
||||
Path: path,
|
||||
Reason: fmt.Sprintf("禁止访问系统目录: %s", fb),
|
||||
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
|
||||
}
|
||||
|
||||
// isSafePath 兼容函数:保持向后兼容
|
||||
// 使用默认配置的路径验证器
|
||||
func isSafePath(path string) bool {
|
||||
validator := NewPathValidator(DefaultConfig())
|
||||
return validator.IsSafe(path)
|
||||
}
|
||||
|
||||
// isSensitivePath 兼容函数:保持向后兼容
|
||||
// 使用默认配置检查敏感路径
|
||||
func isSensitivePath(path string) bool {
|
||||
validator := NewPathValidator(DefaultConfig())
|
||||
return validator.IsSensitive(path)
|
||||
}
|
||||
Reference in New Issue
Block a user