路径遍历攻击与修复
路径遍历攻击(Path Traversal),也称为目录遍历攻击(Directory Traversal),是一种常见的Web安全漏洞。攻击者利用该漏洞可以访问应用程序预期访问范围之外的文件和目录,甚至可能读取、修改或删除服务器上的敏感文件(如配置文件、系统文件、源代码、用户数据等)。
攻击原理
-
核心问题: 应用程序在处理用户提供的输入(通常是文件名或路径参数)时,未进行充分的安全验证和清理,就将其直接用于文件系统操作(如读取、写入文件)。
-
利用方式: 攻击者在输入中注入包含特殊序列(如
../
或..\
)的路径片段,尝试导航到目标目录之外的位置。-
经典示例:
-
假设应用程序通过URL参数加载文件:
https://example.com/loadFile?filename=report.pdf
-
攻击者修改参数:
https://example.com/loadFile?filename=../../../../etc/passwd
-
如果应用程序未正确过滤
../
,它可能会尝试读取服务器上的/etc/passwd
文件(Unix/Linux系统下的用户账户文件)。
-
-
其他变体:
-
编码绕过: 使用URL编码(
%2e%2e%2f
代表../
)、双重编码、UTF-8编码等绕过简单的过滤。 -
绝对路径: 直接注入绝对路径(如
/etc/passwd
或C:\Windows\win.ini
)。 -
空字节注入: 在一些旧版语言或环境中,在注入的路径后添加空字节(
%00
或\0
)来截断应用程序添加的文件后缀。 -
操作系统特定分隔符: 在Windows系统上尝试使用
..\
或反斜杠\
。 -
文件协议: 尝试利用
file://
协议。
-
-
危害
-
敏感信息泄露: 读取服务器配置文件(
/etc/passwd
,/etc/shadow
,web.config
,application.properties
)、源代码、数据库凭证、日志文件、用户私有数据等。 -
系统信息泄露: 获取操作系统版本、安装软件等有助于进一步攻击的信息。
-
拒绝服务 (DoS): 尝试读取大型文件或特殊设备文件导致服务器资源耗尽。
-
文件篡改或删除: 如果应用程序有写入功能且存在路径遍历漏洞,攻击者可能修改或删除关键文件,导致系统瘫痪或数据丢失。
-
进一步入侵的跳板: 获取的信息可用于发起其他攻击(如利用已知漏洞、进行权限提升)。
修复与防御措施(纵深防御)
修复路径遍历漏洞需要采用多层防御策略,不能仅依赖单一方法:
-
输入验证(白名单优先):
-
最佳实践:白名单验证: 如果可能,只允许用户输入预定义的安全值(例如,从下拉列表中选择文件ID或文件名)。这是最安全的做法。
-
严格验证(如果白名单不可行):
-
规范化后验证: 将用户输入解析为规范化的绝对路径。
-
验证起始路径: 确保规范化后的完整路径严格位于应用程序允许访问的根目录(
base directory
)之内。 -
示例 (伪代码):
base_dir = '/var/www/app/uploads/' # 应用程序允许访问的根目录 user_input = request.params['filename']# 1. 规范化路径 (处理 ./ ../ 等) normalized_path = os.path.normpath(os.path.join(base_dir, user_input))# 2. 关键检查:确保规范化路径以 base_dir 开头 (注意使用 os.path.realpath 或 abspath 处理符号链接) if not os.path.realpath(normalized_path).startswith(os.path.realpath(base_dir)):raise SecurityException("Invalid file path requested")# 3. 然后才能安全地使用 normalized_path
-
-
-
清理用户输入(谨慎使用):
-
不要依赖黑名单! 试图过滤掉
../
,..\
,/
,\
等字符是不可靠的,攻击者总能找到编码或变体绕过。 -
如果必须处理原始路径字符串:
-
将用户输入视为文件名部分,而不是路径部分。
-
剥离所有目录分隔符(
/
,\
)和父目录序列(..
)。 -
然后将其与安全的基目录拼接起来(见第1点)。
-
-
-
安全文件操作 API:
-
使用专门设计用于防止路径遍历的API(如果语言或框架提供)。这些API通常强制要求指定一个安全的基目录,并确保所有操作都在该目录下进行。
-
Java 示例 (NIO Path):
Path baseDir = Paths.get("/var/www/app/uploads").toRealPath(); // 获取真实路径,解析符号链接 Path userPath = baseDir.resolve(request.getParameter("filename")).normalize(); // 拼接并规范化if (!userPath.startsWith(baseDir)) {throw new SecurityException("Invalid path"); } // 使用 userPath 操作文件
-
-
应用程序设计:
-
使用间接映射: 不要直接使用用户提供的文件名访问文件系统。使用存储在数据库中的文件ID、哈希值或随机生成的文件名来映射到实际文件。用户只能访问这些标识符。
-
限制文件操作范围: 确保应用程序运行在具有最小必要权限的操作系统用户下。该用户只能访问其严格需要的文件和目录。
-
隔离用户文件: 如果存储用户上传的文件,将不同用户的文件隔离在不同的子目录中。
-
-
Web 服务器/运行时配置:
-
权限最小化: 运行应用程序的进程(如Tomcat, Node.js, PHP-FPM, WSGI)必须使用权限非常有限的专用用户账户。该账户对服务器文件系统的访问权限应被严格限制。
-
文件系统权限: 正确设置操作系统级别的文件和目录权限(
chmod
,chown
),确保只有必要用户和服务有读写执行权限。 -
Web服务器规则: 配置Web服务器(如Nginx, Apache)阻止对敏感目录的直接访问。
-
-
安全编码实践与审计:
-
安全培训: 让开发人员了解路径遍历漏洞及其风险。
-
代码审查: 在代码审查中特别注意所有使用用户输入构造文件路径的地方。
-
自动化扫描: 使用SAST(静态应用安全测试)、DAST(动态应用安全测试)工具扫描应用程序以发现潜在的路径遍历漏洞。
-
渗透测试: 定期进行专业的手动渗透测试。
-
总结
路径遍历漏洞源于对用户输入的不当信任和缺乏足够的验证。修复的关键在于永远不要直接信任用户输入用于文件系统路径。必须采用规范化路径、严格检查最终路径是否位于安全基目录内、使用安全的API以及遵循最小权限原则等多层防御措施。通过结合输入验证、安全设计、安全编码和严格的权限配置,才能有效防范这种危险且常见的漏洞。