【问题标题】:Check change in file extension before file upload在文件上传之前检查文件扩展名的变化
【发布时间】:2021-07-13 22:11:22
【问题描述】:

我想在将文件上传到我们的网站之前检测用户是否恶意更改了文件的扩展名。

我们使用的是 ASP.NET Core 3.1

系统应该只允许上传某些文件类型。例如,用户在上传前将 .exe 重命名为 .pdf,站点应该能够检测并抛出错误。

IFormFile ContentType 不起作用,因为它没有检测到原始文件扩展名。

还有其他方法吗?以某种方式检测文件的原始 Mimetype?

谢谢

【问题讨论】:

  • 不能依赖文件扩展名;您必须检查文件签名或魔术字节。
  • 我认为这不可行。多年来,我一直在 Facebook 上使用 .7z 或 .zip 扩展名绕过它。您可以查看文件中的一些元数据来检查它的真实情况,但覆盖所有可能的扩展名是不可撤销的。
  • 您要求网络服务器猜测远程计算机上的用户在上传文件前 2 天可能做了什么。这不可能。您只是不能依赖扩展来阻止文件类型。使用ContentType 检查浏览器认为的实际文件类型实际上要安全得多。最后,您必须检查文件的标题/幻数

标签: .net asp.net-core mime-types


【解决方案1】:

您可以根据幻数检查文件类型。代码如下:

    public IActionResult FileUpload()
    {
        return View();
    }
    [HttpPost]
    public IActionResult FileUpload(FileViewModel fileviewmodel)
    {
        if (ModelState.IsValid)
        {
            using (var memoryStream = new MemoryStream())
            {
                fileviewmodel.File.CopyToAsync(memoryStream);
                BinaryReader reader = new BinaryReader(memoryStream);
                reader.BaseStream.Position = 0x0; // The offset you are reading the data from    
                byte[] data = reader.ReadBytes(0x10); // Read 16 bytes into an array    
                string data_as_hex = BitConverter.ToString(data);
                //reader.Close();

                // substring to select first 11 characters from hexadecimal array    
                string file_signature = data_as_hex.Substring(0, 11); //pdf: 25-50-44-46  Excel: 50-4B-03-04

                // according to the file_signature value to decide whether need to insert the data into database or return error.
                // Upload the file if less than 2 MB
                if (memoryStream.Length < 2097152)
                {
                    var newfile = new AppFile()
                    {
                        Name = fileviewmodel.Name,  
                        Content = memoryStream.ToArray()
                    };
                     
                }
                else
                {
                    ModelState.AddModelError("File", "The file is too large.");
                }
            }
        }
        return View();
    }

查看页面:

@model WebApplication6.Models.FileViewModel 
<div class="row">
    <div class="col-md-4">
        <form enctype="multipart/form-data" asp-action="FileUpload">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Name" class="control-label"></label>
                <input asp-for="Name" class="form-control" />
                <span asp-validation-for="Name" class="text-danger"></span>
            </div>
            <div class="form-group">
                <dl>
                    <dt>
                        <label asp-for="File"></label>
                    </dt>
                    <dd>
                        <input asp-for="File" type="file">
                    </dd>
                </dl>

            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

测试结果:

对于 .pdf 文件,file_signature 将为 25-50-44-46,对于 .exe 文件,file_signature 值为 4D-5A-90-00。如果将 .exe 文件扩展名更改为.pdf,则file_signature4D-5A-90-00

然后,您可以根据file_signature的值来决定是否需要将数据插入数据库或返回错误。

参考Find File Type From Magic Number Of File In MVC 5

【讨论】:

  • 将文件复制到内存可能会很糟糕,如果不是更糟糕 - 恶意用户可能会将大文件发布到服务器并导致服务器崩溃。 BinaryReader 也不需要只读取 11 个字节。当然没有必要将这些字节转换为字符串并返回
  • 从该站点复制任何内容时,您应该非常非常小心。并首先谷歌特定的短语,以查找文章是从哪里“借来的”。很多时候,原始文章比“借来的”文章要好得多。或者“借用”可能发生在几年前,例如 MSDN 或 docs.microsoft.com,对原始文章进行了编辑以修复错误、错误或添加新信息
猜你喜欢
  • 2013-01-28
  • 1970-01-01
  • 1970-01-01
  • 2017-07-28
  • 1970-01-01
  • 1970-01-01
  • 2015-04-21
  • 2017-06-04
  • 1970-01-01
相关资源
最近更新 更多