What .NET does here is take the uploaded file and look at the file extension. It will then feed the extension into a mime library and generate the relevant content type.
I.e.
Upload a .doc file - ContentType will read: "application/msword"
For this to fail, we could rename an executable file (.exe) to a .doc and upload it. The ContentType will still be application/msword as it's based off the extension.
To overcome this problem, there are two methods we can use. Both of them involve peeking into the file and fetching some data relevant to it's type. So there is a natural trade-off with performance vs. security.
The first example below uses InterOp, and gives us an accurate mime type for the file. The second example uses feature codes, the only down side to using this is where you wish to accept doc and ppt but not xls. This isn't possible as these all share the same feature code (see below).
Two Examples to make decisions based on file/mime type
[System.Runtime.InteropServices.DllImport("urlmon.dll", CharSet = System.Runtime.InteropServices.CharSet.Unicode, ExactSpelling = true, SetLastError = false)]
static extern int FindMimeFromData(IntPtr pBC,
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)] string pwzUrl,
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPArray, ArraySubType = System.Runtime.InteropServices.UnmanagedType.I1, SizeParamIndex = 3)]
byte[] pBuffer, int cbSize,
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)] string pwzMimeProposed, int dwMimeFlags, out IntPtr ppwzMimeOut, int dwReserved);
/// <summary>
/// Ensures that file exists and retrieves the mime type
/// </summary>
/// <param name="fileName">Full path to the file</param>
/// <returns>Returns the Mime Type</returns>
public string GetMimeFromFile(string fileName)
{
IntPtr mimeout;
if (!System.IO.File.Exists(fileName))
throw new System.IO.FileNotFoundException(fileName + " not found");
int MaxContent = (int)new System.IO.FileInfo(fileName).Length;
if (MaxContent > 4096) MaxContent = 4096;
System.IO.FileStream fs = System.IO.File.OpenRead(fileName);
byte[] buf = new byte[MaxContent];
fs.Read(buf, 0, MaxContent);
fs.Close();
int result = FindMimeFromData(IntPtr.Zero, fileName, buf, MaxContent, null, 0, out mimeout, 0);
if (result != 0)
throw System.Runtime.InteropServices.Marshal.GetExceptionForHR(result);
string mime = System.Runtime.InteropServices.Marshal.PtrToStringUni(mimeout);
System.Runtime.InteropServices.Marshal.FreeCoTaskMem(mimeout);
return mime;
}
/// <summary>
/// Reads the file to determine the feature code.
/// /* Extension name specification [Feature codes]
/// *7173 gif
/// *255216 jpg
/// *13780 png
/// *6677 bmp
/// *239187 txt,aspx,asp,sql
/// *208207 xls,doc,ppt
/// *6063 xml
/// *6033 htm,html
/// *4742 js
/// *8075 xlsx,docx,pptx,mmap,zip,msi
/// *8297 rar
/// *01 accdb,mdb
/// *7790 exe,dll
/// *5666 psd
/// *255254 rdp
/// *10056 bt
/// *64101 bat
/// *3780 pdf
/// */
/// </summary>
/// <param name="hifile">Posted file following the upload process</param>
/// <returns>Returns weather the file type is allowed</returns>
public bool IsAllowedExtension(HttpPostedFile hifile)
{
bool ret = false;
System.IO.BinaryReader r = new System.IO.BinaryReader(hifile.InputStream);
string fileclass = string.Empty;
byte buffer;
try
{
buffer = r.ReadByte();
fileclass = buffer.ToString();
buffer = r.ReadByte();
fileclass += buffer.ToString();
}
catch
{
return false;
}
r.Close();
String[] fileType = {"208207", "8075", "3780"}; // Place allowed file types here
for (int i = 0; i < fileType.Length; i++)
{
if (fileclass == fileType[i])
{
ret = true;
break;
}
}
return ret;
}
No comments:
Post a Comment