ASP.NET Core 文件上传 之 文件签名验证

ASP.NET Core 文件上传

系列之 文件签名验证

一、前言

在最近的开发过程中遇到一个文件上传的需求。由于目标框架是 asp.net core 5。遂打开 MSDN 翻阅 文件上传 的相关内容,在学习过程中发现在上传文件时可以对文件签名进行验证。

文件的签名由文件开头部分中的前几个字节确定。 可以使用这些字节指示扩展名是否与文件内容匹配。

private static readonly Dictionary<string, List<byte[]>> _fileSignature = 
    new Dictionary<string, List<byte[]>>
{
    { ".jpeg", new List<byte[]>
        {
            new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 },
            new byte[] { 0xFF, 0xD8, 0xFF, 0xE2 },
            new byte[] { 0xFF, 0xD8, 0xFF, 0xE3 },
        }
    },
};

以上是官方提供的例子。并且告诉我们若要获取其他文件签名,可以参阅 文件签名数据库 和官方文件规范。

在查看过数据库之后大致明白,我们只需要有对应文件的签名,我们就可以验证上传到服务器上的文件内容是不是确实是它的扩展名指定的文件。 可是文件签名数据库上的内容多大18页,而且并非所有的扩展名都是我们需要验证的文件,而且对于上传的文件支持也不仅仅只是一两个扩展名这么简单,所以很明显,我们需要一种方式来帮我们自动化的获取我们需要的文件扩展名的签名,并且这些签名数据库需要我们能够静态保存,而不是需要的时候再去 签名数据库网站上去取用(因为这效率很低)。于是便有了这篇随笔。

二、实现思路及过程

  1. 首先,我查看了 文件签名数据库 上的网页源码,并没有找到可以直接获取数据的 API,我们仅仅能够获取包含数据的 html。
  2. 既然可以获取到 html ,那我们也可以通过正则这样的方式来快速的取出我们需要的数据。
  3. 通过分析网页,我们需要的数据都是包含在如下的标签之中:
     <span id = "results"><a href="/index.php?page=search&search=ACCDB&mode=EXT">ACCDB</a></span>
     <span id = "results"><a href="/index.php?page=search&search=000100005374616E6461726420414345204442&mode=SIG">00 01 00 00 53 74 61 6E 64 61 72 64 20 41 43 45 20 44 42 </a></span>
    
    得到以下规律:
    1. 数据都是包含在 id = results<span/> 标签
    2. results 都是 两个一组的出现,第一个标签的内容为 文件扩展名,第二个标签的内容为 文件签名 (十六进制)
  4. 检索一下怎么使用正则来获取我们想要的标签吧 [转载]C#用正则表达式 获取网页源代码标签的属性或值
  5. 但是并没有我们需要根据id来获取的方法,不过没事,根据上面得到的标签规律,我们稍微改造一下:
    public static class HtmlExtensions
    {
        /// <summary>
        /// 获取访问签名数据库网页的 url
        /// </summary>
        /// <param name="ext"></param>
        /// <returns></returns>
        public static string ToUrl(this string ext)
        {
            if (ext.StartsWith("."))
            { ext = ext[1..]; }
            return $"https://www.filesignatures.net/index.php?search={ext.ToLower()}&mode=EXT";
        }
    
        /// <summary>  
        /// 获取 html 文本中指定标签的值  
        /// </summary>  
        /// <param name="html">html 文本</param>  
        /// <param name="title">标签</param>  
        /// <returns>值</returns>  
        public static string GetContent(this string html, string title)
        {
            string tmpStr = string.Format("<{0}[^>]*?>(?<Text>[^<]*)</{1}>", title, title); //获取<title>之间内容  
    
            Match TitleMatch = Regex.Match(html, tmpStr, RegexOptions.IgnoreCase);
    
            return TitleMatch.Groups["Text"].Value;
        }
    
        /// <summary>  
        /// 获取 html 文本中id为指定值的标签  
        /// </summary>  
        /// <param name="html">html 文本</param>  
        /// <param name="title">标签</param>  
        /// <param name="id">Id</param>  
        /// <returns>属性</returns>  
        public static List<string> GetMarkups(this string html, string title, string id)
        {
            string tmpStr = $"<{title}(.*?)id\\s?=\\s?\"{id}\"\\s?>.*?</{title}>"; //获取<title>之间内容  
    
            var TitleMatchs = Regex.Matches(html, tmpStr, RegexOptions.IgnoreCase);
    
            return TitleMatchs.Select(x => x.Value).ToList();
        }
    }
    
  6. 那一切准备就绪,我们可以开始根据需要获取对应的文件签名的内容了。

三、获取 .NET 项目中可用的 文件签名代码

根据前言中的代码样式,我们定义好需要的文件后缀名,然后在一个简单的循环中便可以完成我们需要的代码,生成 *.txt 后,直接文本内容粘贴到项目中文件签名验证的地方即可。

如果需要其它语言或者项目的文件签名代码,只需要参照 Main 方法,并遵循目标语言的语法规则来修改即可。

以下是我用到的文件签名验证字典:

public static readonly Dictionary<string, List<byte[]>> FileSignature = new Dictionary<string, List<byte[]>>
{
    { ".accdb", new List<byte[]> { new byte[] { 0x00, 0x01, 0x00, 0x00, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x41, 0x43, 0x45, 0x20, 0x44, 0x42 } } },
    { ".aiff", new List<byte[]> { new byte[] { 0x46, 0x4F, 0x52, 0x4D, 0x00 } } },
    { ".asf", new List<byte[]> { new byte[] { 0x30, 0x26, 0xB2, 0x75, 0x8E, 0x66, 0xCF, 0x11 } } },
    { ".asx", new List<byte[]> { new byte[] { 0x3C } } },
    { ".au", new List<byte[]> { new byte[] { 0x64, 0x6E, 0x73, 0x2E }, new byte[] { 0x2E, 0x73, 0x6E, 0x64 } } },
    { ".avi", new List<byte[]> { new byte[] { 0x52, 0x49, 0x46, 0x46 } } },
    { ".bin", new List<byte[]> { new byte[] { 0x42, 0x4C, 0x49, 0x32, 0x32, 0x33, 0x51 } } },
    { ".bmp", new List<byte[]> { new byte[] { 0x42, 0x4D } } },
    { ".cab", new List<byte[]> { new byte[] { 0x49, 0x53, 0x63, 0x28 }, new byte[] { 0x4D, 0x53, 0x43, 0x46 } } },
    { ".cat", new List<byte[]> { new byte[] { 0x30 } } },
    { ".chm", new List<byte[]> { new byte[] { 0x49, 0x54, 0x53, 0x46 } } },
    { ".class", new List<byte[]> { new byte[] { 0xCA, 0xFE, 0xBA, 0xBE } } },
    { ".cmx", new List<byte[]> { new byte[] { 0x52, 0x49, 0x46, 0x46 } } },
    { ".cod", new List<byte[]> { new byte[] { 0x4E, 0x61, 0x6D, 0x65, 0x3A, 0x20 } } },
    { ".csh", new List<byte[]> { new byte[] { 0x63, 0x75, 0x73, 0x68, 0x00, 0x00, 0x00, 0x02 } } },
    { ".cur", new List<byte[]> { new byte[] { 0x00, 0x00, 0x02, 0x00 } } },
    { ".dib", new List<byte[]> { new byte[] { 0x42, 0x4D } } },
    { ".dll", new List<byte[]> { new byte[] { 0x4D, 0x5A } } },
    { ".doc", new List<byte[]> { new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }, new byte[] { 0x0D, 0x44, 0x4F, 0x43 }, new byte[] { 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1, 0x00 }, new byte[] { 0xDB, 0xA5, 0x2D, 0x00 }, new byte[] { 0xEC, 0xA5, 0xC1, 0x00 } } },
    { ".docx", new List<byte[]> { new byte[] { 0x50, 0x4B, 0x03, 0x04 }, new byte[] { 0x50, 0x4B, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00 } } },
    { ".dot", new List<byte[]> { new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 } } },
    { ".dsp", new List<byte[]> { new byte[] { 0x23, 0x20, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73 } } },
    { ".dtd", new List<byte[]> { new byte[] { 0x07, 0x64, 0x74, 0x32, 0x64, 0x64, 0x74, 0x64 } } },
    { ".eml", new List<byte[]> { new byte[] { 0x58, 0x2D }, new byte[] { 0x52, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x2D, 0x50 }, new byte[] { 0x46, 0x72, 0x6F, 0x6D } } },
    { ".eps", new List<byte[]> { new byte[] { 0xC5, 0xD0, 0xD3, 0xC6 }, new byte[] { 0x25, 0x21, 0x50, 0x53, 0x2D, 0x41, 0x64, 0x6F } } },
    { ".exe", new List<byte[]> { new byte[] { 0x4D, 0x5A } } },
    { ".fdf", new List<byte[]> { new byte[] { 0x25, 0x50, 0x44, 0x46 } } },
    { ".flv", new List<byte[]> { new byte[] { 0x46, 0x4C, 0x56 } } },
    { ".gif", new List<byte[]> { new byte[] { 0x47, 0x49, 0x46, 0x38 } } },
    { ".gz", new List<byte[]> { new byte[] { 0x1F, 0x8B, 0x08 } } },
    { ".hlp", new List<byte[]> { new byte[] { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF }, new byte[] { 0x3F, 0x5F, 0x03, 0x00 }, new byte[] { 0x4C, 0x4E, 0x02, 0x00 } } },
    { ".hqx", new List<byte[]> { new byte[] { 0x28, 0x54, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69 } } },
    { ".ico", new List<byte[]> { new byte[] { 0x00, 0x00, 0x01, 0x00 } } },
    { ".jar", new List<byte[]> { new byte[] { 0x50, 0x4B, 0x03, 0x04 }, new byte[] { 0x5F, 0x27, 0xA8, 0x89 }, new byte[] { 0x4A, 0x41, 0x52, 0x43, 0x53, 0x00 }, new byte[] { 0x50, 0x4B, 0x03, 0x04, 0x14, 0x00, 0x08, 0x00 } } },
    { ".jfif", new List<byte[]> { new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 }, new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 } } },
    { ".jpe", new List<byte[]> { new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 }, new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 } } },
    { ".jpeg", new List<byte[]> { new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 }, new byte[] { 0xFF, 0xD8, 0xFF, 0xE2 }, new byte[] { 0xFF, 0xD8, 0xFF, 0xE3 } } },
    { ".jpg", new List<byte[]> { new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 }, new byte[] { 0xFF, 0xD8, 0xFF, 0xE1 }, new byte[] { 0xFF, 0xD8, 0xFF, 0xE8 } } },
    { ".lit", new List<byte[]> { new byte[] { 0x49, 0x54, 0x4F, 0x4C, 0x49, 0x54, 0x4C, 0x53 } } },
    { ".lzh", new List<byte[]> { new byte[] { 0x2D, 0x6C, 0x68 } } },
    { ".manifest", new List<byte[]> { new byte[] { 0x3C, 0x3F, 0x78, 0x6D, 0x6C, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3D } } },
    { ".mdb", new List<byte[]> { new byte[] { 0x00, 0x01, 0x00, 0x00, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x4A, 0x65, 0x74, 0x20, 0x44, 0x42 } } },
    { ".mid", new List<byte[]> { new byte[] { 0x4D, 0x54, 0x68, 0x64 } } },
    { ".midi", new List<byte[]> { new byte[] { 0x4D, 0x54, 0x68, 0x64 } } },
    { ".mmf", new List<byte[]> { new byte[] { 0x4D, 0x4D, 0x4D, 0x44, 0x00, 0x00 } } },
    { ".mny", new List<byte[]> { new byte[] { 0x00, 0x01, 0x00, 0x00, 0x4D, 0x53, 0x49, 0x53, 0x41, 0x4D, 0x20, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65 } } },
    { ".mov", new List<byte[]> { new byte[] { 0x6D, 0x6F, 0x6F, 0x76 }, new byte[] { 0x66, 0x72, 0x65, 0x65 }, new byte[] { 0x6D, 0x64, 0x61, 0x74 }, new byte[] { 0x77, 0x69, 0x64, 0x65 }, new byte[] { 0x70, 0x6E, 0x6F, 0x74 }, new byte[] { 0x73, 0x6B, 0x69, 0x70 } } },
    { ".mp3", new List<byte[]> { new byte[] { 0x49, 0x44, 0x33 } } },
    { ".mpg", new List<byte[]> { new byte[] { 0x00, 0x00, 0x01, 0xBA }, new byte[] { 0x00, 0x00, 0x01, 0xB3 } } },
    { ".msi", new List<byte[]> { new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }, new byte[] { 0x23, 0x20 } } },
    { ".ocx", new List<byte[]> { new byte[] { 0x4D, 0x5A } } },
    { ".one", new List<byte[]> { new byte[] { 0xE4, 0x52, 0x5C, 0x7B, 0x8C, 0xD8, 0xA7, 0x4D } } },
    { ".p10", new List<byte[]> { new byte[] { 0x64, 0x00, 0x00, 0x00 } } },
    { ".pcx", new List<byte[]> { new byte[] { 0x0A, 0x02, 0x01, 0x01 }, new byte[] { 0x0A, 0x03, 0x01, 0x01 }, new byte[] { 0x0A, 0x05, 0x01, 0x01 } } },
    { ".pdf", new List<byte[]> { new byte[] { 0x25, 0x50, 0x44, 0x46 } } },
    { ".pgm", new List<byte[]> { new byte[] { 0x50, 0x35, 0x0A } } },
    { ".png", new List<byte[]> { new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A } } },
    { ".pps", new List<byte[]> { new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 } } },
    { ".ppt", new List<byte[]> { new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }, new byte[] { 0x00, 0x6E, 0x1E, 0xF0 }, new byte[] { 0x0F, 0x00, 0xE8, 0x03 }, new byte[] { 0xA0, 0x46, 0x1D, 0xF0 }, new byte[] { 0xFD, 0xFF, 0xFF, 0xFF, 0x0E, 0x00, 0x00, 0x00 }, new byte[] { 0xFD, 0xFF, 0xFF, 0xFF, 0x1C, 0x00, 0x00, 0x00 }, new byte[] { 0xFD, 0xFF, 0xFF, 0xFF, 0x43, 0x00, 0x00, 0x00 } } },
    { ".pptx", new List<byte[]> { new byte[] { 0x50, 0x4B, 0x03, 0x04 }, new byte[] { 0x50, 0x4B, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00 } } },
    { ".psd", new List<byte[]> { new byte[] { 0x38, 0x42, 0x50, 0x53 } } },
    { ".psp", new List<byte[]> { new byte[] { 0x7E, 0x42, 0x4B, 0x00 } } },
    { ".pub", new List<byte[]> { new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 } } },
    { ".qxd", new List<byte[]> { new byte[] { 0x00, 0x00, 0x49, 0x49, 0x58, 0x50, 0x52 }, new byte[] { 0x00, 0x00, 0x4D, 0x4D, 0x58, 0x50, 0x52 } } },
    { ".ra", new List<byte[]> { new byte[] { 0x2E, 0x52, 0x4D, 0x46, 0x00, 0x00, 0x00, 0x12 }, new byte[] { 0x2E, 0x72, 0x61, 0xFD, 0x00 } } },
    { ".ram", new List<byte[]> { new byte[] { 0x72, 0x74, 0x73, 0x70, 0x3A, 0x2F, 0x2F } } },
    { ".rar", new List<byte[]> { new byte[] { 0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00 } } },
    { ".rgb", new List<byte[]> { new byte[] { 0x01, 0xDA, 0x01, 0x01, 0x00, 0x03 } } },
    { ".rm", new List<byte[]> { new byte[] { 0x2E, 0x52, 0x4D, 0x46 } } },
    { ".rmi", new List<byte[]> { new byte[] { 0x52, 0x49, 0x46, 0x46 } } },
    { ".rpm", new List<byte[]> { new byte[] { 0xED, 0xAB, 0xEE, 0xDB } } },
    { ".rtf", new List<byte[]> { new byte[] { 0x7B, 0x5C, 0x72, 0x74, 0x66, 0x31 } } },
    { ".sit", new List<byte[]> { new byte[] { 0x53, 0x49, 0x54, 0x21, 0x00 }, new byte[] { 0x53, 0x74, 0x75, 0x66, 0x66, 0x49, 0x74, 0x20 } } },
    { ".snp", new List<byte[]> { new byte[] { 0x4D, 0x53, 0x43, 0x46 } } },
    { ".spl", new List<byte[]> { new byte[] { 0x00, 0x00, 0x01, 0x00 } } },
    { ".swf", new List<byte[]> { new byte[] { 0x43, 0x57, 0x53 }, new byte[] { 0x46, 0x57, 0x53 } } },
    { ".tar", new List<byte[]> { new byte[] { 0x75, 0x73, 0x74, 0x61, 0x72 } } },
    { ".tif", new List<byte[]> { new byte[] { 0x49, 0x20, 0x49 }, new byte[] { 0x49, 0x49, 0x2A, 0x00 }, new byte[] { 0x4D, 0x4D, 0x00, 0x2A }, new byte[] { 0x4D, 0x4D, 0x00, 0x2B } } },
    { ".tiff", new List<byte[]> { new byte[] { 0x49, 0x20, 0x49 }, new byte[] { 0x49, 0x49, 0x2A, 0x00 }, new byte[] { 0x4D, 0x4D, 0x00, 0x2A }, new byte[] { 0x4D, 0x4D, 0x00, 0x2B } } },
    { ".vcf", new List<byte[]> { new byte[] { 0x42, 0x45, 0x47, 0x49, 0x4E, 0x3A, 0x56, 0x43 } } },
    { ".vsd", new List<byte[]> { new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 } } },
    { ".wav", new List<byte[]> { new byte[] { 0x52, 0x49, 0x46, 0x46 } } },
    { ".wks", new List<byte[]> { new byte[] { 0x0E, 0x57, 0x4B, 0x53 }, new byte[] { 0xFF, 0x00, 0x02, 0x00, 0x04, 0x04, 0x05, 0x54 } } },
    { ".wma", new List<byte[]> { new byte[] { 0x30, 0x26, 0xB2, 0x75, 0x8E, 0x66, 0xCF, 0x11 } } },
    { ".wmf", new List<byte[]> { new byte[] { 0xD7, 0xCD, 0xC6, 0x9A } } },
    { ".wmv", new List<byte[]> { new byte[] { 0x30, 0x26, 0xB2, 0x75, 0x8E, 0x66, 0xCF, 0x11 } } },
    { ".wmz", new List<byte[]> { new byte[] { 0x50, 0x4B, 0x03, 0x04 } } },
    { ".wps", new List<byte[]> { new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 } } },
    { ".wri", new List<byte[]> { new byte[] { 0x31, 0xBE }, new byte[] { 0x32, 0xBE }, new byte[] { 0xBE, 0x00, 0x00, 0x00, 0xAB } } },
    { ".xdr", new List<byte[]> { new byte[] { 0x3C } } },
    { ".xla", new List<byte[]> { new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 } } },
    { ".xls", new List<byte[]> { new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }, new byte[] { 0x09, 0x08, 0x10, 0x00, 0x00, 0x06, 0x05, 0x00 }, new byte[] { 0xFD, 0xFF, 0xFF, 0xFF, 0x10 }, new byte[] { 0xFD, 0xFF, 0xFF, 0xFF, 0x1F }, new byte[] { 0xFD, 0xFF, 0xFF, 0xFF, 0x22 }, new byte[] { 0xFD, 0xFF, 0xFF, 0xFF, 0x23 }, new byte[] { 0xFD, 0xFF, 0xFF, 0xFF, 0x28 }, new byte[] { 0xFD, 0xFF, 0xFF, 0xFF, 0x29 } } },
    { ".xlsx", new List<byte[]> { new byte[] { 0x50, 0x4B, 0x03, 0x04 }, new byte[] { 0x50, 0x4B, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00 } } },
    { ".xml", new List<byte[]> { new byte[] { 0x3C, 0x3F, 0x78, 0x6D, 0x6C, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3D, 0x22, 0x31, 0x2E, 0x30, 0x22, 0x3F, 0x3E } } },
    { ".xps", new List<byte[]> { new byte[] { 0x50, 0x4B, 0x03, 0x04 } } },
    { ".zip", new List<byte[]> { new byte[] { 0x50, 0x4B, 0x03, 0x04 }, new byte[] { 0x50, 0x4B, 0x4C, 0x49, 0x54, 0x45 }, new byte[] { 0x50, 0x4B, 0x53, 0x70, 0x58 }, new byte[] { 0x50, 0x4B, 0x05, 0x06 }, new byte[] { 0x50, 0x4B, 0x07, 0x08 }, new byte[] { 0x57, 0x69, 0x6E, 0x5A, 0x69, 0x70 }, new byte[] { 0x50, 0x4B, 0x03, 0x04, 0x14, 0x00, 0x01, 0x00 } } },
};

posted on 2021-05-25 12:00  View12138  阅读(766)  评论(1编辑  收藏  举报

导航