首页/安全/漏洞与攻击面速查/路径穿越(目录遍历)防护
Web 漏洞原理与防护55 条

路径穿越(目录遍历)防护

路径穿越通过 ../ 或编码变体让文件操作跳出预期目录,读取或覆盖系统文件;防护核心是规范化路径后校验前缀(或改用文件 ID 映射),而不是简单替换 ../。

漏洞与攻击面速查安全更新于 2026-10-13

路径穿越是什么

路径穿越(又称目录遍历)指文件操作接受用户可控的路径片段,输入中的上级目录记号让访问跳出预期目录,从而读取或覆盖系统文件。它的成因是把「拼接路径」当作安全操作:只要用户能影响路径的任何一段,就可能引入跨越目录的成分。防护的核心不是过滤某个字符串,而是先做路径规范化(把相对成分解析掉),再校验结果仍落在允许的基准目录内;更彻底的做法是让用户提交逻辑标识,由服务端映射到磁盘上的随机文件名。

基本信息

风险类别OWASP Top 10 2021 A03 注入类;CWE-22
常见入口文件下载、图片预览、附件路径、模板与日志查看、导入导出
危害读取配置文件与凭据、读取源码、覆盖或写入文件
防护顺序取文件名 → 规范化 → 前缀校验 → 映射到固定存储名
语言差异Linux 用正斜杠,Windows 同时接受反斜杠与盘符
编码变体百分号编码、双重编码、Unicode 变形在解码后才生效

典型场景

  • 附件与图片下载接口按文件名取磁盘路径
  • 模板或报表功能允许指定模板文件名
  • 日志查看页面按日期与文件名读取日志
  • 导入功能解压压缩包时未校验包内文件名
  • 静态资源代理按路径参数回源取文件
  • 备份与导出功能把用户提供的名称拼进输出路径

安全实现示意(Python)

安全实现示意(Python)
import os
BASE = os.path.realpath('/srv/files')
name = os.path.basename(user_input)            # 先剥离路径成分
target = os.path.realpath(os.path.join(BASE, name))
if not target.startswith(BASE + os.sep):
    raise PermissionError('path out of base')
# 更稳的做法:文件名与数据库 ID 映射,磁盘文件使用 UUID 命名
# 注意 realpath 之后再比较,比较时要带路径分隔符,避免前缀相似的目录被误判

绕过手法与防护要点

绕过手法说明防护要点
双重编码编码后再解码成上级目录记号在解码之后、调用文件系统之前校验
多级相对路径用多层上级记号跳出目录规范化后再校验前缀
前缀相似目录目标目录名以基准目录名开头比较时补上路径分隔符
Windows 反斜杠用反斜杠或盘符切换路径统一按目标平台规则规范化
压缩包内路径解压时写出到目录之外解压前逐个校验条目路径
多轮编码(%2e%2e%2f 等)会在框架解码后变成 ../;校验必须发生在解码之后、文件系统调用之前。
最省心的方案是把用户可见名称与磁盘存储名解耦:用户传 ID 或经过校验的名称,服务端查表得到随机存储名,路径穿越在结构上就不存在了。

易错点

  • 只在 URL 层替换一次 ../ 就放行:双重编码与 Windows 反斜杠变体可绕过
  • 前缀校验未加分隔符:/srv/files2 会被误判为 /srv/files 前缀
  • 只校验不做规范化:路径里的相对成分未解析,校验结果与实际访问的路径不一致
  • 忽略压缩包解压:包内文件名同样需要逐条校验,包含符号链接时要额外处理
  • 把根目录写进可写路径:即使读取被拦住,写入操作仍可能覆盖配置或脚本文件
  • 只修被通报的参数:同类的下载、预览与模板接口往往共用同一套路径拼接逻辑

数据来源与参考

  • OWASP Path Traversal 说明
  • OWASP WSTG 路径穿越测试章节
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌