什么是目录遍历?
目录遍历(也称为文件路径遍历)是一个Web安全漏洞,它使攻击者可以读取运行应用程序的服务器上的任意文件。这可能包括应用程序代码和数据,后端系统的凭据以及敏感的操作系统文件。在某些情况下,攻击者可能能够写入服务器上的任意文件,从而允许他们修改应用程序数据或行为,并最终完全控制服务器。
通过目录遍历读取任意文件
考虑一个显示要出售商品图像的购物应用程序。图像通过一些HTML加载,如下所示:
<img src="/loadImage?filename=218.png">
该loadImage网址将filename参数,返回指定的文件的内容。映像文件本身存储在该位置的磁盘上/var/www/images/。为了返回图像,应用程序将请求的文件名附加到此基本目录,并使用文件系统API读取文件的内容。在上述情况下,应用程序将从以下文件路径读取:
/var/www/images/218.png
该应用程序没有针对目录遍历攻击采取任何防御措施,因此攻击者可以请求以下URL从服务器的文件系统中检索任意文件:
https://insecure-website.com/loadImage?filename=../../../etc/passwd
这将导致应用程序从以下文件路径读取:
/var/www/images/../../../etc/passwd
该序列…/在文件路径中有效,并且意味着在目录结构中上一级。三个连续的…/序列从/var/www/images/文件系统根目录开始,因此实际读取的文件是:
/etc/passwd
在基于Unix的操作系统上,这是一个标准文件,其中包含在服务器上注册的用户的详细信息。
在Windows上,…/和…\都是有效的目录遍历序列,而检索标准操作系统文件的等效攻击将是:
https://insecure-website.com/loadImage?filename=..\..\..\windows\win.ini
如果应用程序从用户提供的文件名中剥离或阻止目录遍历序列,则可能可以使用多种技术绕过防御。
- 可以使用文件系统根目录的绝对路径(例如)filename=/etc/passwd直接引用文件,而无需使用任何遍历序列。
- 可以使用嵌套的遍历序列,例如…//或…/,当内部序列被剥离时,它们将还原为简单的遍历序列。
- 您可能可以使用各种非标准编码(例如…%c0%af或…%252f)来绕过输入过滤器。
- 如果应用程序要求用户提供的文件名必须以所需的基本文件夹(例如)开头/var/www/images,则可以包括所需的基本文件夹,后跟适当的遍历序列。例如:
filename=/var/www/images/../../../etc/passwd
- 如果应用程序要求用户提供的文件名必须以预期的文件扩展名(例如)结尾.png,则可以使用空字节有效终止要求的扩展名之前的文件路径。例如:
filename=…/…/…/etc/passwd%00.png
如何防止目录遍历攻击
防止文件路径遍历漏洞的最有效方法是避免将用户提供的输入完全传递给文件系统API。可以重写许多执行此操作的应用程序功能,以更安全的方式提供相同的行为。
如果认为不可避免的是将用户提供的输入传递给文件系统API,则应同时使用两层防御,以防止受到攻击:
- 应用程序应在处理之前验证用户输入。理想情况下,验证应与允许值的白名单进行比较。如果所需的功能无法做到这一点,则验证应验证输入内容仅包含允许的内容,例如纯字母数字字符。
- 验证提供的输入后,应用程序应将输入附加到基本目录,并使用平台文件系统API规范化路径。它应验证规范化路径以预期的基本目录开头。
以下是一些简单的Java代码示例,用于根据用户输入来验证文件的规范路径:
File file = new File(BASE_DIRECTORY, userInput);
if (file.getCanonicalPath().startsWith(BASE_DIRECTORY)) {
// process file
}