87 lines
2.1 KiB
Python
87 lines
2.1 KiB
Python
"""
|
|
路径安全检查模块
|
|
防止路径遍历攻击和非法访问
|
|
"""
|
|
from pathlib import Path
|
|
from typing import Tuple
|
|
|
|
def is_safe_path(base_path: Path, target_path: Path) -> bool:
|
|
"""
|
|
检查目标路径是否在基础路径内
|
|
|
|
Args:
|
|
base_path: 基础路径(如用户根目录)
|
|
target_path: 目标路径
|
|
|
|
Returns:
|
|
是否安全
|
|
"""
|
|
try:
|
|
# 解析为绝对路径
|
|
base = base_path.resolve()
|
|
target = target_path.resolve()
|
|
|
|
# 检查target是否在base下
|
|
return str(target).startswith(str(base))
|
|
except Exception:
|
|
return False
|
|
|
|
|
|
def validate_filename(filename: str) -> Tuple[bool, str]:
|
|
"""
|
|
验证文件名是否合法
|
|
|
|
Args:
|
|
filename: 文件名
|
|
|
|
Returns:
|
|
(是否合法, 错误信息)
|
|
"""
|
|
# 禁止的字符
|
|
forbidden_chars = ['<', '>', ':', '"', '|', '?', '*', '\0']
|
|
|
|
for char in forbidden_chars:
|
|
if char in filename:
|
|
return False, f"文件名包含非法字符: {char}"
|
|
|
|
# 禁止的文件名
|
|
forbidden_names = [
|
|
'CON', 'PRN', 'AUX', 'NUL',
|
|
'COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9',
|
|
'LPT1', 'LPT2', 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9'
|
|
]
|
|
|
|
name_without_ext = Path(filename).stem.upper()
|
|
if name_without_ext in forbidden_names:
|
|
return False, f"文件名不允许: {filename}"
|
|
|
|
# 检查路径遍历
|
|
if '..' in filename or filename.startswith('/') or filename.startswith('\\'):
|
|
return False, "文件名包含路径遍历字符"
|
|
|
|
return True, ""
|
|
|
|
|
|
def sanitize_path(path_str: str) -> str:
|
|
"""
|
|
清理路径字符串
|
|
|
|
Args:
|
|
path_str: 原始路径字符串
|
|
|
|
Returns:
|
|
清理后的路径
|
|
"""
|
|
# 移除开头的斜杠
|
|
path_str = path_str.lstrip('/')
|
|
path_str = path_str.lstrip('\\')
|
|
|
|
# 标准化路径分隔符
|
|
path_str = path_str.replace('\\', '/')
|
|
|
|
# 移除连续的斜杠
|
|
while '//' in path_str:
|
|
path_str = path_str.replace('//', '/')
|
|
|
|
return path_str
|