C# 删除文件时检查文件路径

C# 删除文件时检查文件路径,c#,asp.net,.net,C#,Asp.net,.net,如果我有一个web方法,在调用时删除一个文件,并且它接受三个参数(cNum、year和fileName)。我需要担心这种方法的漏洞吗。我唯一能想到的就是使用。\\\\\\\将delete驱动到文件夹结构的更上层。这应该很容易去除。但是还有什么我应该担心的吗 [WebMethod(EnableSession = true, Description = "Method for deleting files uploaded by customers")] [ScriptMet

如果我有一个web方法,在调用时删除一个文件,并且它接受三个参数(cNum、year和fileName)。我需要担心这种方法的漏洞吗。我唯一能想到的就是使用
。\\\\\\\
将delete驱动到文件夹结构的更上层。这应该很容易去除。但是还有什么我应该担心的吗

[WebMethod(EnableSession = true, 
           Description = "Method for deleting files uploaded by customers")]
[ScriptMethod(ResponseFormat = ResponseFormat.Xml)]
public Boolean deleteCustFiles(string cNum, string year, string fileName)
{
    try
    {
        if (String.IsNullOrEmpty(cNum) 
            || String.IsNullOrEmpty(year) 
            || String.IsNullOrEmpty(fileName))
                throw new Exception();

        string path = Server.MapPath(@"~\docs\custFiles\" 
                                        + year + @"\" 
                                        + cNum + @"\" + fileName);
        File.Delete(path);
    }
    catch
    {
        throw new Exception("Unable to delete file");
    }
    return true;
}

我建议使用上的来清除filename参数,如下所示:

public Boolean deleteCustFiles(string cNum, string year, string fileName)
{
    // Cleanse fileName.
    fileName = Path.GetFileName(fileName);
string path = Server.MapPath(@"~\docs\custFiles\")
path = Path.Combine(path, year);
path = Path.Combine(path, cNum);
path = Path.Combine(path, fileName);
GetFileName
方法从一个路径中剥离所有目录信息,这正是您在这里要做的

输入如下:

..\..\..\filename.ext
你会得到:

filename.ext
作为回报,您不必担心有人注入一条路径,该路径将从您所针对的目录中逃逸(假设此文件名是用户输入,或者来自一个开放端点,在该端点中有人可以输入他们想要的任何输入)

然后,这允许您将自定义路径附加到
文件名

当然,这只适用于所有文件都位于预定义的目录中的情况,看起来确实如此

但是,这不会处理删除用户无权访问的文件。如果文件属于该目录中的另一个用户,则此处不检查是否存在这种情况(但如果所有用户都有权删除这些文件,则可以)

此外,您可能希望使用
Path
类上的来组合路径,如下所示:

public Boolean deleteCustFiles(string cNum, string year, string fileName)
{
    // Cleanse fileName.
    fileName = Path.GetFileName(fileName);
string path = Server.MapPath(@"~\docs\custFiles\")
path = Path.Combine(path, year);
path = Path.Combine(path, cNum);
path = Path.Combine(path, fileName);
如果您使用的是.NET 4.0或更高版本,则可以使用:

最后,如果可能的话(对于一个完整的解决方案),为了使它更加安全,您应该在文件系统级别启用权限

如果您正在模拟该用户或使用受约束的用户帐户来处理所有请求,则应仅授予该用户对
~\docs\custFiles\
目录(以及任何子目录)的访问权限


用户帐户不应访问该目录之上的任何内容。

最好检查文件名和目录名,如果它们是否为有效文件名,请对照此字符数组进行检查:

编辑:

您可能还应该像下面这样验证年份和数字:


bool valid=int.TryParse(num,out temp) 

您可能还想考虑在文件系统上使用内置安全性,以防止用户删除不想要的目录中的文件。如果web应用程序是在只有权删除一个目录中的文件的特定用户下运行的,则无论用户尝试什么,该应用程序都无权执行删除

此外,这将使维护(即:添加新目录)非常容易,而无需重新部署应用程序

然后,您可以捕获访问无效访问尝试的尝试,并根据需要对其进行处理

[WebMethod(EnableSession = true, 
    Description = "Method for deleting files uploaded by customers")]
[ScriptMethod(ResponseFormat = ResponseFormat.Xml)]
public Boolean deleteCustFiles(string cNum, string year, string fileName)
{
    try
    {
        if (String.IsNullOrEmpty(cNum) || String.IsNullOrEmpty(year) ||
            String.IsNullOrEmpty(fileName))
            throw new Exception();
        string path = 
            Server.MapPath(@"~\docs\custFiles\" + year + @"\" + cNum + 
                @"\" + fileName);
        File.Delete(path);
    }
    catch (System.Security.SecurityException e)
    {
        throw new Exception("Unauthorized attempt to delete file");
    }
    catch
    {
        throw new Exception("Unable to delete file");
    }

    return true;
}

不确定是否可以使用通配符,但这可能是另一个问题…在你创建文件之前。删除我肯定会检查文件是否存在,这将允许你提供更好的消息,让用户知道文件不存在,而不是一般的“无法删除文件”消息。你不应该抛出
异常
,或者如果您这样做,不要抛出
异常
文件NotFoundException
更好。或者返回false哪个更好。为什么要尝试验证年份和数字?只有当子目录不是目录结构中的唯一子目录,并且用户无法访问这些其他子目录时,这才有用。我不希望出现这种情况,因为我希望
custFiles
完全由用户而不是代码驱动。关于其中文件/目录的任何信息都应该完全存储在其他地方。@casperOne,从问题的角度来看,他似乎需要使用
String.IsNullOrEmpty()
验证年份和编号,这表明这可能取决于用户输入,并且他不确定变量值,因此,额外的验证可能有助于确保这些变量完全符合预期。“可能有用”-您没有显示它可能有用的地方。假设有两个目录,1998和1999。如果用户输入为“abcd”,则该目录不存在,并且不会删除任何内容。如果有人合法地发送“1988”,那么就没有问题了,该文件将被删除。但是,如果有人恶意地发送“1999”(假设该文件在两个文件中)来删除人们认为应该在1998年删除的内容,那么解析整数在这里没有效果;它没有阻止用户访问他们不应该拥有的目录。它不会增加任何额外的安全性。@casperOne,在其中一个变量中不可能有
吗?是的,在这种情况下,解析整数可能会有所帮助,但您可能希望使用
Path.GetFileName
来代替它,并将其完全剥离。虽然文件系统的内置安全性是一个很好的补充,您可能正在从输入传播攻击。如果用户对输入有一定的期望,则仍应注意用户输入的内容。在这种情况下,绝对有一种情况,即目录信息不会出现。@casperOne:我不明白你可能传播攻击的意思。您能详细说明一下吗?例如,如果传入了
。\..\filename.ext
。当然,您不应该向实际执行删除的用户授予任何两个目录的权限,但这不是一个完整的解决方案。您应该始终清理输入。