基于后端的文件上传安全性验证

该功能主要是为了解决WebShell文件上传安全漏洞的问题

1、创建文件后缀类型的枚举

public enum E_FileExtension
    {
        NONE = 0,
        EXE = 7790,
        APK = 8075,
        JPG= 255216,
        PNG= 13780,
        GIF = 7173,
        BMP = 6677,
        DOCX = 208207,
        DOC = 208207,
        PDF = 3780,
    }

2、创建文件验证类

public class FileCheckExtension
    {
        // 提供按照UploadFile和Byte[]进行的过滤验证和算法;
        private static object obj = new object();         // 锁定对象
        private static FileCheckExtension fce;            // 验证类实体
        private List<E_FileExtension> filterList = new List<E_FileExtension>();   // 过滤的格式集合
        private FileCheckExtension(List<E_FileExtension> _filterList)
        {
            init(_filterList);
        }

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="_filterList">过滤的格式集合</param>
        private void init(List<E_FileExtension> _filterList)
        {
            filterList = _filterList;
        }
        /// <summary>
        /// 单例模式主入口
        /// </summary>
        /// <param name="_filterList">过滤的格式集合</param>
        /// <returns>FileCheckExtension</returns>
        public static FileCheckExtension BulderFCE(List<E_FileExtension> _filterList)
        {
            if (fce == null)
            {
                lock (obj)
                {
                    if (fce == null)
                    {
                        fce = new FileCheckExtension(_filterList);
                    }
                }
            }
            return fce;
        }
        /// <summary>
        /// 验证上传控件的文件类型
        /// </summary>
        /// <param name="fu">FileUpload</param>
        /// <returns>类型枚举</returns>
        public E_FileExtension GetFileExtension(FileUpload fu)
        {
            Byte[] bytesContent = new Byte[2];
            fu.PostedFile.InputStream.Read(bytesContent, 0, 2);
            return GetFileExtension(bytesContent);
        }
        /// <summary>
        /// 验证Byte数组的文件类型
        /// </summary>
        /// <param name="bytes">Byte[]</param>
        /// <returns>类型枚举</returns>
        public E_FileExtension GetFileExtension(Byte[] bytes)
        {
            E_FileExtension eFX = E_FileExtension.NONE;
            MemoryStream ms = new MemoryStream(bytes);
            BinaryReader br = new BinaryReader(ms);
            string fileTop = string.Empty;
            byte buffer;
            try
            {
                buffer = br.ReadByte();
                fileTop = buffer.ToString();
                buffer = br.ReadByte();
                fileTop += buffer.ToString();
                foreach (E_FileExtension efx in filterList)
                {
                    if (System.Int32.Parse(fileTop).Equals((int)efx))
                    {
                        eFX = efx;
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                br.Close();
                ms.Dispose();
            }
            return eFX;
        }
        /// <summary>
        /// 验证文件后缀名是否合法
        /// </summary>
        /// <param name="fu"></param>
        /// <returns>true or false</returns>
        public bool ExtensionVerify(FileUpload fu)
        {
            string fullName = fu.PostedFile.FileName;
            string exeName = string.Empty;
            if (fullName != string.Empty)
            {
                exeName = fullName.Substring(fullName.LastIndexOf(".") + 1);
                //// 对于特殊文件格式txt,直接放行
                //if (exeName.ToLower().Equals("txt") || exeName.ToLower().Equals("log"))
                //{
                //    return CheckIsTextFile(fu);
                //}
            }
            E_FileExtension efe = GetFileExtension(fu);
            if ((int)efe == 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        /// <summary>
        /// 验证文件后缀名是否合法
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns>true or false</returns>
        public bool ExtensionVerify(Byte[] bytes)
        {
            E_FileExtension efe = GetFileExtension(bytes);
            if ((int)efe == 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        public bool CheckIsTextFile(FileUpload fu)
        {
            Byte[] bytesContent = new Byte[fu.PostedFile.ContentLength];
            fu.PostedFile.InputStream.Read(bytesContent, 0, fu.PostedFile.ContentLength);
            MemoryStream ms = new MemoryStream(bytesContent);
            bool isTextFile = true;
            try
            {
                int i = 0;
                int length = (int)ms.Length;
                byte data;
                while (i < length && isTextFile)
                {
                    data = (byte)ms.ReadByte();
                    isTextFile = (data != 0);
                    i++;
                }
                return isTextFile;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (ms != null)
                {
                    ms.Close();
                }

            }
        }

    }

3、对上传的文件进行安全性检查

public string UploadFile(HttpServerUtility server)
        {
            string result = "";
            try
            {
                System.Web.HttpFileCollection _file = System.Web.HttpContext.Current.Request.Files;
                string path = "Files\\APP";
                //文件名  
                string name = _file[0].FileName;

                //文件格式  
                string _tp = System.IO.Path.GetExtension(name);
                name = Guid.NewGuid().ToString().ToLower() + _tp;
                // 组合需要验证的枚举数组(只让上传apk和exe后缀的文件,改后缀也不好使,说不让上传就不让上传)
                List<E_FileExtension> fes = new List<E_FileExtension> { E_FileExtension.EXE, E_FileExtension.APK };
                // 单例启动验证类
                FileCheckExtension fcx = FileCheckExtension.BulderFCE(fes);
                // 采用文件头验证
                int fileLen = _file[0].ContentLength;
                byte[] array = new byte[fileLen];
                _file[0].InputStream.Read(array, 0, fileLen);

                bool bl = fcx.ExtensionVerify(array);
                if (bl)
                {
                    //System.Web.IHttpModule
                    string newPath = server.MapPath("..\\" + path);
                    if (!Directory.Exists(newPath))
                    {
                        Directory.CreateDirectory(newPath);
                    }
                    newPath = newPath + "\\" + name;
                    _file[0].SaveAs(newPath);
                    result = path + "\\" + name; ;
                }
                else
                {
                    result = "error";
                }


            }
            catch
            {
                result = "error";
            }
            return result;
        }

 

posted @ 2022-09-15 09:33  桎梏110  阅读(319)  评论(0编辑  收藏  举报
Live2D