Files
srs-spi/main/main_test.go
haibo.chen 2aa65de911 security
2025-10-15 16:04:35 +08:00

248 lines
6.3 KiB
Go

package main
import (
"path"
"path/filepath"
"strings"
"testing"
)
// TestPathTraversalPrevention 测试路径遍历防护
func TestPathTraversalPrevention(t *testing.T) {
baseDir := "/var/www/html"
tests := []struct {
name string
inputPath string
shouldFail bool
reason string
}{
{
name: "Normal file",
inputPath: "/index.html",
shouldFail: false,
reason: "Normal file access should be allowed",
},
{
name: "Subdirectory file",
inputPath: "/css/style.css",
shouldFail: false,
reason: "Subdirectory access should be allowed",
},
{
name: "Deep subdirectory",
inputPath: "/js/lib/jquery.min.js",
shouldFail: false,
reason: "Deep subdirectory access should be allowed",
},
{
name: "Parent directory traversal",
inputPath: "/../etc/passwd",
shouldFail: true,
reason: "Parent directory traversal should be blocked",
},
{
name: "Double parent traversal",
inputPath: "/../../etc/passwd",
shouldFail: true,
reason: "Double parent traversal should be blocked",
},
{
name: "Multiple parent traversal",
inputPath: "/../../../etc/passwd",
shouldFail: true,
reason: "Multiple parent traversal should be blocked",
},
{
name: "Mixed path with parent",
inputPath: "/css/../../etc/passwd",
shouldFail: true,
reason: "Mixed path with parent should be blocked",
},
{
name: "Dot slash path",
inputPath: "/./index.html",
shouldFail: false,
reason: "Dot slash should be cleaned but allowed",
},
{
name: "Complex traversal",
inputPath: "/css/../js/../../../etc/passwd",
shouldFail: true,
reason: "Complex traversal should be blocked",
},
{
name: "Root path",
inputPath: "/",
shouldFail: false,
reason: "Root path should be allowed",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// 模拟修复后的路径验证逻辑
// 首先检查原始路径是否包含 ".."
containsDoubleDotInOriginal := strings.Contains(tt.inputPath, "..")
// 如果原始路径包含 "..",直接阻止
if containsDoubleDotInOriginal {
if !tt.shouldFail {
t.Errorf("%s: Path contains '..' but should be allowed: %s", tt.reason, tt.inputPath)
}
t.Logf("Input: %s, Contains '..': true, Blocked: true (early check)", tt.inputPath)
return
}
// 清理路径
cleanPath := path.Clean(tt.inputPath)
// 构建文件路径
filePath := filepath.Join(baseDir, cleanPath)
// 获取绝对路径
absDir, err := filepath.Abs(baseDir)
if err != nil {
t.Fatalf("Failed to get absolute path of base dir: %v", err)
}
absFilePath, err := filepath.Abs(filePath)
if err != nil {
t.Fatalf("Failed to get absolute path of file: %v", err)
}
// 验证路径是否在允许的目录内
isOutsideBaseDir := !strings.HasPrefix(absFilePath, absDir)
// 判断是否应该被阻止
shouldBlock := isOutsideBaseDir
if tt.shouldFail && !shouldBlock {
t.Errorf("%s: Expected path to be blocked, but it was allowed. Path: %s, Clean: %s, Abs: %s",
tt.reason, tt.inputPath, cleanPath, absFilePath)
}
if !tt.shouldFail && shouldBlock {
t.Errorf("%s: Expected path to be allowed, but it was blocked. Path: %s, Clean: %s, Abs: %s",
tt.reason, tt.inputPath, cleanPath, absFilePath)
}
// 额外的日志信息用于调试
t.Logf("Input: %s, Clean: %s, Outside base: %v, Blocked: %v",
tt.inputPath, cleanPath, isOutsideBaseDir, shouldBlock)
})
}
}
// TestPathCleanBehavior 测试 path.Clean 的行为
func TestPathCleanBehavior(t *testing.T) {
tests := []struct {
input string
expected string
}{
{"/index.html", "/index.html"},
{"/../etc/passwd", "/etc/passwd"},
{"/./index.html", "/index.html"},
{"/css/../index.html", "/index.html"},
{"//double//slash", "/double/slash"},
{"/trailing/slash/", "/trailing/slash"},
{"/./././index.html", "/index.html"},
}
for _, tt := range tests {
t.Run(tt.input, func(t *testing.T) {
result := path.Clean(tt.input)
if result != tt.expected {
t.Errorf("path.Clean(%q) = %q, expected %q", tt.input, result, tt.expected)
}
})
}
}
// TestAbsolutePathValidation 测试绝对路径验证
func TestAbsolutePathValidation(t *testing.T) {
// 使用临时目录进行测试
baseDir := t.TempDir()
tests := []struct {
name string
path string
shouldFail bool
}{
{
name: "File in base directory",
path: "index.html",
shouldFail: false,
},
{
name: "File in subdirectory",
path: "css/style.css",
shouldFail: false,
},
{
name: "Attempt to escape with parent",
path: "../outside.txt",
shouldFail: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cleanPath := path.Clean(tt.path)
filePath := filepath.Join(baseDir, cleanPath)
absDir, err := filepath.Abs(baseDir)
if err != nil {
t.Fatalf("Failed to get absolute path: %v", err)
}
absFilePath, err := filepath.Abs(filePath)
if err != nil {
t.Fatalf("Failed to get absolute file path: %v", err)
}
isOutside := !strings.HasPrefix(absFilePath, absDir)
if tt.shouldFail && !isOutside {
t.Errorf("Expected path to be outside base dir, but it wasn't: %s", absFilePath)
}
if !tt.shouldFail && isOutside {
t.Errorf("Expected path to be inside base dir, but it wasn't: %s", absFilePath)
}
})
}
}
// BenchmarkPathValidation 性能基准测试
func BenchmarkPathValidation(b *testing.B) {
baseDir := "/var/www/html"
testPath := "/css/style.css"
b.ResetTimer()
for i := 0; i < b.N; i++ {
cleanPath := path.Clean(testPath)
_ = strings.Contains(cleanPath, "..")
filePath := filepath.Join(baseDir, cleanPath)
absDir, _ := filepath.Abs(baseDir)
absFilePath, _ := filepath.Abs(filePath)
_ = strings.HasPrefix(absFilePath, absDir)
}
}
// BenchmarkPathValidationMalicious 恶意路径的性能测试
func BenchmarkPathValidationMalicious(b *testing.B) {
baseDir := "/var/www/html"
testPath := "/../../../etc/passwd"
b.ResetTimer()
for i := 0; i < b.N; i++ {
cleanPath := path.Clean(testPath)
_ = strings.Contains(cleanPath, "..")
filePath := filepath.Join(baseDir, cleanPath)
absDir, _ := filepath.Abs(baseDir)
absFilePath, _ := filepath.Abs(filePath)
_ = strings.HasPrefix(absFilePath, absDir)
}
}