客户端与服务器端的文件名清理

时间:2022-02-13 16:24:41

When uploading files from many separate web pages and controllers, my C# backend breaks when a file with an HTML entity in the name gets uploaded:

从许多单独的网页和控制器上传文件时,当名称中包含HTML实体的文件上传时,我的C#后端会中断:

An exception of type 'System.Web.HttpRequestValidationException' occurred in System.Web.Mvc.dll but was not handled in user code

Additional information: A potentially dangerous Request.Files value was detected from the client (filename="...for_files_#US2023103...").

Notice the HTML entity # in the name, which should just be #. I could go through every web page's JS and force the JS to change/decode the HTML entities on the client side (lots of little changes) or I could change the server side code to handle this, but I'm not sure the server side method could be done without exposing the server to vulnerabilities.

注意HTML实体#在名称中,应该只是#。我可以浏览每个网页的JS并强制JS在客户端更改/解码HTML实体(许多小的更改)或者我可以更改服务器端代码来处理这个,但我不确定服务器端可以在不将服务器暴露给漏洞的情况下完成方法。

To prevent this from being an opinionated question, I explicitly ask:

为了防止这是一个固执己问的问题,我明确地问:

Is there any way to escape/validate file names on the server side, without throwing an exception, and without exposing the server to vulnerabilities?

有没有办法在服务器端转义/验证文件名,而不抛出异常,并且没有将服务器暴露给漏洞?

Here is the code I am trying to use for replacing the filename:

这是我试图用来替换文件名的代码:

        if (requestContext.HttpContext.Request.Files.Count > 0)
        {
            foreach (HttpPostedFileBase file in requestContext.HttpContext.Request.Files)
            {
                file.FileName = System.Net.WebUtility.HtmlDecode(file.FileName);
            }
        }

This of course is not allowed because FileName is a readonly property of HttpPostedFileBase. I am thinking that it may be smart to check the filename, if it has HTML entities, or semicolons, then instantiate a new HttpPostedFileBase object with the corrected name.

这当然是不允许的,因为FileName是HttpPostedFileBase的只读属性。我认为检查文件名,如果它有HTML实体或分号,然后用更正的名称实例化一个新的HttpPostedFileBase对象可能是明智的。

1 个解决方案

#1


0  

I don't know which .net framework you use but but you can try making use of the HttpUtility.HtmlDecode method.

我不知道您使用哪个.net框架,但您可以尝试使用HttpUtility.HtmlDecode方法。

Note about security: sanitisation/validation MUST be made on the server side. Client side is ONLY for user experience. Nothing that you do on the client side is really secure since you have no way to ensure it was actually done without re-doing it on the server (that was my rant about the title)

关于安全性的注意事项:必须在服务器端进行消毒/验证。客户端仅用于用户体验。你在客户端做的一切都不是很安全,因为你没有办法确保它没有在服务器上重新执行它(这是我对标题的咆哮)

You can try that

你可以试试

if (requestContext.HttpContext.Request.Files.Count > 0)
{
    var finalDir = "path/to/dir"
    foreach (HttpPostedFileBase file in requestContext.HttpContext.Request.Files)
    {
        var decodedFileName = System.Net.WebUtility.HtmlDecode(file.FileName);

        try
        {
            // Will not overwrite if the destination file already exists.
            if(filename.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
                throw new Exception('invalid name');
            else
                File.Copy(decodedFileName , Path.Combine(finalDir, Guid.NewGuid()));
        }

        // Catch exception if the file was already copied.
        catch (IOException copyError)
        {
            Console.WriteLine(copyError.Message);
        }
    }
}

or even easier, as per this SO post

甚至更容易,根据这篇SO帖子

if (requestContext.HttpContext.Request.Files.Count > 0)
{
    foreach (HttpPostedFileBase file in requestContext.HttpCont
    {
        file.SaveAs(Path.Combine("destination/path/", Guid.NewGuid());
    }
}

#1


0  

I don't know which .net framework you use but but you can try making use of the HttpUtility.HtmlDecode method.

我不知道您使用哪个.net框架,但您可以尝试使用HttpUtility.HtmlDecode方法。

Note about security: sanitisation/validation MUST be made on the server side. Client side is ONLY for user experience. Nothing that you do on the client side is really secure since you have no way to ensure it was actually done without re-doing it on the server (that was my rant about the title)

关于安全性的注意事项:必须在服务器端进行消毒/验证。客户端仅用于用户体验。你在客户端做的一切都不是很安全,因为你没有办法确保它没有在服务器上重新执行它(这是我对标题的咆哮)

You can try that

你可以试试

if (requestContext.HttpContext.Request.Files.Count > 0)
{
    var finalDir = "path/to/dir"
    foreach (HttpPostedFileBase file in requestContext.HttpContext.Request.Files)
    {
        var decodedFileName = System.Net.WebUtility.HtmlDecode(file.FileName);

        try
        {
            // Will not overwrite if the destination file already exists.
            if(filename.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
                throw new Exception('invalid name');
            else
                File.Copy(decodedFileName , Path.Combine(finalDir, Guid.NewGuid()));
        }

        // Catch exception if the file was already copied.
        catch (IOException copyError)
        {
            Console.WriteLine(copyError.Message);
        }
    }
}

or even easier, as per this SO post

甚至更容易,根据这篇SO帖子

if (requestContext.HttpContext.Request.Files.Count > 0)
{
    foreach (HttpPostedFileBase file in requestContext.HttpCont
    {
        file.SaveAs(Path.Combine("destination/path/", Guid.NewGuid());
    }
}