从许多单独的网页和 Controller 上传文件时,当上传名称中包含 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...").
注意名称中的 HTML 实体 #
,它应该只是 #
。我可以遍历每个网页的 JS 并强制 JS 在客户端更改/解码 HTML 实体(很多小的更改)或者我可以更改服务器端代码来处理这个问题,但我不确定服务器端方法可以在不使服务器暴露于漏洞的情况下完成。
为了防止这是一个自以为是的问题,我明确地问:
有没有什么方法可以在服务器端转义/验证文件名,而不会抛出异常,也不会使服务器暴露在漏洞之下?
这是我尝试用来替换文件名的代码:
if (requestContext.HttpContext.Request.Files.Count > 0)
{
foreach (HttpPostedFileBase file in requestContext.HttpContext.Request.Files)
{
file.FileName = System.Net.WebUtility.HtmlDecode(file.FileName);
}
}
这当然是不允许的,因为 FileName 是 HttpPostedFileBase
的只读属性。我认为检查文件名可能是明智的,如果它有 HTML 实体或分号,然后用更正的名称实例化一个新的 HttpPostedFileBase 对象。
最佳答案
我不知道您使用的是哪个 .net 框架,但您可以尝试使用 HttpUtility.HtmlDecode
方法。
关于安全性的注意事项:清理/验证必须在服务器端进行。客户端仅用于用户体验。你在客户端做的任何事情都不是真正安全的,因为如果不在服务器上重新做,你就无法确保它确实完成了(这是我对标题的提示)
你可以试试
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);
}
}
}
或者更简单,根据 this SO post
if (requestContext.HttpContext.Request.Files.Count > 0)
{
foreach (HttpPostedFileBase file in requestContext.HttpCont
{
file.SaveAs(Path.Combine("destination/path/", Guid.NewGuid());
}
}
关于javascript - 客户端与服务器端的文件名清理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46916290/