所有文章 > 技术杂货铺 > .NET路径遍历指南:示例与预防
.NET路径遍历指南:示例与预防

.NET路径遍历指南:示例与预防

在本文中,我们将探讨路径遍历攻击的概念,以及可以采取哪些方法来缓解它们。

我们将首先简要解释什么是路径遍历攻击。然后我们将探讨一些您可以在网上找到的典型示例。最后,我们将提出一些可能的解决方案来解决这些漏洞。

阅读完本文后,您将对路径遍历的概念有基本的了解,并有资格在您的项目中实施缓解策略。

注意:本文面向 .NET 开发人员。因此,我们希望您对 .NET 开发堆栈有基本的了解。 

什么是路径遍历?

广义上讲,路径遍历是一种利用服务器端有缺陷的访问控制实现的攻击,特别是对于文件访问。

在路径遍历攻击中,恶意行为者会尝试通过向应用程序注入恶意用户输入来访问服务器中的受限文件。 

可以将其视为 SQL 注入,不过是在目录而不是数据库上。

现在,很明显,为什么用户未经授权访问服务器文件是一件可怕的事情已经很清楚了。一个心怀不轨的人可以利用这种权力破坏我们的系统并接管平台。 

这就是为什么建立适当的安全机制至关重要。

这是对路径遍历概念的简短而简单的解释,进一步的探索超出了本文的范围。

在那篇文章中,我们更深入地探讨了造成此漏洞的奇怪因素以及服务器运行的系统为何如此重要。

现在,让我们继续看一些路径遍历攻击的例子。

路径遍历攻击

那么,您可能会问,典型的路径遍历攻击是什么样的?

嗯,就这么简单。

../../etc/passwd

很令人惊奇吧?

路径遍历本质上就是找到进入开发人员和应用程序不打算让您访问的文件夹的方法。因此,如果您对路径逻辑和 Linux 或命令行有基本的了解,您就可以进入未受保护的应用程序。

现在,让我们看一些具体类型的路径遍历攻击。

相对路径攻击

上面我们举例说明了相对路径攻击。 

通过利用用户输入验证或缺乏验证,攻击者可能会尝试访问服务器中的受限文件。在这种情况下,passwd文件包含我们在服务器上的机密。

当然,缓解此漏洞的一个简单方法是应用适当的用户输入验证。通过包含一个像path.normalize()一样简单的命令并清理用户输入(顺便说一句,这是您应该始终做的事情),您可以避免以后出现很多麻烦和问题。

毒化空字节攻击

在 HTTP 请求中的字符串末尾提供空字节或\0,允许攻击者绕过用于清理用户输入的字符串验证并访问未经授权的文件和目录。

在网络上看起来会是什么样子?嗯,就像这样。

/../../../../../../../../../../../../../../../../etc/passwd%00

你看到末尾的%00 了吗?不幸的是,我们糟糕的验证最终会将其转换为\0.txt\0之类的内容,并可能授予对passwd文件的访问权限。哎呀!

为了防止这种攻击破坏我们的安全,您只需使用以下内容验证用户输入。

if (user_input.indexOf('\0') !== -1) {
return respond('Access denied');
}

比较简单,对吧?

正如我们之前提到的,路径遍历攻击并不是非常复杂。相反,它们依赖于糟糕的访问控制实现或更新不良的代码导致的边缘情况漏洞。 

然而,它们可能非常危险,我们应尽可能地减轻它们的影响。 

好消息是,这并不难。

.NET 路径遍历指南:示例和预防图像

路径遍历攻击的其他缓解方法

幸运的是,我们可以采取许多措施来弥补安全方面的可能漏洞。我们在此列出了一些。

路径前缀验证

但是,如何在您的应用程序中允许某种程度的遍历呢?在某些情况下,您可能希望应用程序允许用户在不同的文件夹中找到文件,例如个人资料图片和文章,它们都位于各自的文件夹中。 

您可以实现硬编码路径验证,例如请求特定资源时使用的变量。但是,这样做可能会使自己遭受前缀路径遍历攻击。

如果用户可以在应用程序中输入点和斜线而不验证生成的字符串,则攻击者可以自由遍历目录。 

为了缓解这种情况,我们需要验证用户输入不包含这些字符并将其删除或直接显示错误。

像这样简单的事情就可以了:

public bool IsPathTraversing(string path) {
bool result = false;

if (String.IsNullOrWhiteSpace(path)) {
return result;
}

// Url decode to reveal sneaky encoded attempts e.g. '%2f' (/) or '%2e%2e%2f' (../)
var decodedPath = HttpUtility.UrlDecode(path);

if (decodedPath.Contains("/") ||
decodedPath.Contains(@"\") ||
decodedPath.Contains("$") ||
decodedPath.Contains("..") ||
decodedPath.Contains("?")) {

result = true;
}

return result;
}

安全列表

安全列表是一种简单且相对有效的方法,可以减少漏洞利用的可能性。当然,您不会总是能够使用它,但您应该尽可能使用它。

安全列表的一个简单示例是验证用户输入是否符合预定义的某个标准。例如,如果您已将应用程序编码为仅创建和处理包含小写字母数字字符的文件,则可以验证用户是否仅输入此类字符。

protected string readFile(string location) {
Regex regex = new Regex(@"([a-zA-Z0-9\s_\\.\-:])+(.dat)$");
Match match = regex.Match(location);

if (match.Success) {
if (File.Exists(location)) {
using (StreamReader reader = new StreamReader(location)) {
return reader.ReadToEnd();
}
} else {
return "File not found";
}
} else {
return "File name not valid";
}
}

通过向用户输入添加此验证,您可以获得额外的保护层来抵御恶意攻击。

路径连接

最后,解决所有这些差距并为我们可能面临的所有潜在漏洞创建一个强大的解决方案的一种方法是实施一个包含所有这些测试并创建安全的最终路径字符串的通用验证方案。

解决方案的一个例子看起来像这样。

protected string readFile(string location) {
Regex regex = new Regex(@"([a-zA-Z0-9\s_\\.\-:])+(.dat)$");
Match match = regex.Match(location);

if (match.Success) {
if (File.Exists(location) && Path.GetFullPath(location).StartsWith(@"C:\Applications\Documents", StringComparison.OrdinalIgnoreCase)) {
using (StreamReader reader = new StreamReader(location)) {
return reader.ReadToEnd();
}
} else {
return "File not found";
}
} else {
return "File name not valid";
}
}

正如您所看到的,我们已经整合了所有已经讨论过的检查和验证,以涵盖任何可能对我们系统滥用的行为。

在路径遍历发生之前阻止它

尽管看起来很简单,但必须确保我们执行良好的路径遍历安全策略并覆盖应用程序中尽可能多的潜在漏洞。

技术将继续发展,更加强大和全面的解决方案将缓解这些问题。 

然而,请不要忘记,只要我们采取彻底而富有创意的方法,我们总能弥补系统的不足。

鉴于 .NET 是一个如此成熟和强大的平台,有多种方法可以解决这个问题。只需确保找到满足您需求的方法并充分测试您的方法和实现即可。

文章来源:.NET Path Traversal Guide: Examples and Prevention

#你可能也喜欢这些API文章!