基于后端的文件上传安全性验证
该功能主要是为了解决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; }