CodeQL 文档

路径表达式中使用的非受控数据

ID: cs/path-injection
Kind: path-problem
Security severity: 7.5
Severity: error
Precision: high
Tags:
   - security
   - external/cwe/cwe-022
   - external/cwe/cwe-023
   - external/cwe/cwe-036
   - external/cwe/cwe-073
   - external/cwe/cwe-099
Query suites:
   - csharp-code-scanning.qls
   - csharp-security-extended.qls
   - csharp-security-and-quality.qls

点击查看 CodeQL 代码库中的查询

访问由用户控制的路径可能允许攻击者访问意外的资源。这可能导致敏感信息泄露或被删除,或者攻击者能够通过修改意外文件来影响行为。

从用户控制的数据简单构建的路径可能是绝对路径,或者可能包含意外的特殊字符,例如“..”。此类路径可能指向文件系统上的任何位置。

建议

在使用用户输入构造文件路径之前对其进行验证。

常见的验证方法包括检查规范化路径是否是相对路径且不包含任何“..”组件,或者检查路径是否包含在安全文件夹中。您应该使用哪种方法取决于应用程序如何使用路径,以及路径是否应该是单个路径组件。

如果路径应该是单个路径组件(例如文件名),则可以检查输入中是否存在任何路径分隔符(“/”或“\”)或“..”序列,如果找到任何内容,则拒绝输入。

请注意,删除“../”序列_不够_,因为输入可能仍然包含路径分隔符后跟“..”。例如,如果仅删除“../”序列,则输入“…/…//”仍将导致字符串“../”。

最后,最简单(但限制最多)的选择是使用安全模式的允许列表,并确保用户输入与其中一种模式匹配。

示例

在此示例中,从 HTTP 请求中读取用户提供的文件名,然后使用该文件名访问文件并将其发送回用户。但是,恶意用户可以在文件系统的任何位置输入文件名,例如“/etc/passwd”或“../../../etc/passwd”。

using System;
using System.IO;
using System.Web;

public class TaintedPathHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext ctx)
    {
        string filename = ctx.Request.QueryString["path"];
        // BAD: This could read any file on the filesystem.
        ctx.Response.Write(File.ReadAllText(filename));
    }
}

如果输入应该只是一个文件名,则可以检查它是否不包含任何路径分隔符或“..”序列。

using System;
using System.IO;
using System.Web;

public class TaintedPathHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext ctx)
    {
        string filename = ctx.Request.QueryString["path"];
        // GOOD: ensure that the filename has no path separators or parent directory references
        if (filename.Contains("..") || filename.Contains("/") || filename.Contains("\\"))
        {
            ctx.Response.StatusCode = 400;
            ctx.Response.StatusDescription = "Bad Request";
            ctx.Response.Write("Invalid path");
            return;
        }
        ctx.Response.Write(File.ReadAllText(filename));
    }
}

如果输入应该在特定目录内,则可以检查解析后的路径是否仍然包含在该目录内。

using System;
using System.IO;
using System.Web;

public class TaintedPathHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext ctx)
    {
        string filename = ctx.Request.QueryString["path"];
        
        string user = ctx.User.Identity.Name;
        string publicFolder = Path.GetFullPath("/home/" + user + "/public");
        string filePath = Path.GetFullPath(Path.Combine(publicFolder, filename));

        // GOOD: ensure that the path stays within the public folder
        if (!filePath.StartsWith(publicFolder + Path.DirectorySeparatorChar))
        {
            ctx.Response.StatusCode = 400;
            ctx.Response.StatusDescription = "Bad Request";
            ctx.Response.Write("Invalid path");
            return;
        }
        ctx.Response.Write(File.ReadAllText(filename));
    }
}

参考

  • ©GitHub, Inc.
  • 条款
  • 隐私