path_utils.py 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. """
  2. 路径验证工具
  3. """
  4. import re
  5. import os
  6. from fastapi import HTTPException
  7. def validate_path(path: str, allow_root: bool = False) -> str:
  8. """
  9. 验证和清理文件路径,防止路径遍历攻击
  10. Args:
  11. path: 要验证的路径
  12. allow_root: 是否允许根路径 "/"
  13. Returns:
  14. 清理后的路径
  15. Raises:
  16. HTTPException: 如果路径无效
  17. """
  18. if not path:
  19. raise HTTPException(status_code=400, detail="路径不能为空")
  20. # 移除开头的斜杠(MinIO 规范)
  21. if path.startswith('/'):
  22. path = path[1:]
  23. # 检查路径遍历攻击
  24. if '..' in path or path.startswith('/') or '//' in path:
  25. raise HTTPException(status_code=400, detail="无效的路径格式,不允许路径遍历")
  26. # 检查危险字符
  27. dangerous_chars = ['<', '>', '|', '\0', '\r', '\n']
  28. for char in dangerous_chars:
  29. if char in path:
  30. raise HTTPException(status_code=400, detail=f"路径包含非法字符: {char}")
  31. # 检查路径长度
  32. if len(path) > 1024:
  33. raise HTTPException(status_code=400, detail="路径长度超过限制")
  34. return path
  35. def sanitize_filename(filename: str) -> str:
  36. """
  37. 清理文件名,移除危险字符
  38. Args:
  39. filename: 原始文件名
  40. Returns:
  41. 清理后的文件名
  42. """
  43. if not filename:
  44. raise HTTPException(status_code=400, detail="文件名不能为空")
  45. filename = os.path.basename(filename)
  46. # 移除路径分隔符
  47. filename = filename.replace('/', '').replace('\\', '')
  48. # 移除危险字符
  49. dangerous_chars = ['<', '>', '|', ':', '"', '?', '*', '\0']
  50. for char in dangerous_chars:
  51. filename = filename.replace(char, '_')
  52. # 限制长度
  53. if len(filename) > 255:
  54. name, ext = filename.rsplit('.', 1) if '.' in filename else (filename, '')
  55. filename = name[:250] + ('.' + ext if ext else '')
  56. return filename