3

How do I check the file type of a file uploaded using FileUploader control in an ASP.NET C# webpage?

  1. I tried checking file extension, but it obviously fails when a JPEG image (e.g. Leonardo.jpg) is renamed to have a PDF's extension (e.g. Leonardo.pdf).

  2. I tried

    FileUpload1.PostedFile.ContentType.ToLower().Equals("application/pdf")
    

    but this fails as the above code behaves the same way as the first did.

Is there any other way to check the actual file type, not just the extension?

I looked at ASP.NET how to check type of the file type irrespective of extension.

Edit: I tried below code from one of the posts in stackoverflow. But this down't work. Any idea about this.

/// <summary>
/// This class allows access to the internal MimeMapping-Class in System.Web
/// </summary>
class MimeMappingWrapper
{
  static MethodInfo getMimeMappingMethod;

    static MimeMappingWrapper() {
    // dirty trick - Assembly.LoadWIthPartialName has been deprecated
    Assembly ass = Assembly.LoadWithPartialName("System.Web");
    Type t = ass.GetType("System.Web.MimeMapping");

    getMimeMappingMethod t.GetMethod("GetMimeMapping", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public));
}

/// <summary>
/// Returns a MIME type depending on the passed files extension
/// </summary>
/// <param name="fileName">File to get a MIME type for</param>
/// <returns>MIME type according to the files extension</returns>
public static string GetMimeMapping(string fileName) {
    return (string)getMimeMappingMethod.Invoke(null, new[] { fileName });
}
}
Community
  • 1
  • 1
crazyTechie
  • 2,517
  • 12
  • 32
  • 41

3 Answers3

6

Dont use File Extensions to work out MIME Types, instead use "Winista" for binary analysis.

Say someone renames an exe with a jpg extension. You can still determine the real file format. It doesn't detect swf's or flv's but does pretty much every other well known format and you can get a hex editor to add more files it can detect.

Download Winista: here or my mirror or my GitHub https://github.com/MeaningOfLights/MimeDetect.

Where Winista fails to detect the real file format, I've resorted back to the URLMon method:

public class urlmonMimeDetect
{
    [DllImport(@"urlmon.dll", CharSet = CharSet.Auto)]
    private extern static System.UInt32 FindMimeFromData(
        System.UInt32 pBC,
        [MarshalAs(UnmanagedType.LPStr)] System.String pwzUrl,
        [MarshalAs(UnmanagedType.LPArray)] byte[] pBuffer,
        System.UInt32 cbSize,
        [MarshalAs(UnmanagedType.LPStr)] System.String pwzMimeProposed,
        System.UInt32 dwMimeFlags,
        out System.UInt32 ppwzMimeOut,
        System.UInt32 dwReserverd
    );

public string GetMimeFromFile(string filename)
{
    if (!File.Exists(filename))
        throw new FileNotFoundException(filename + " not found");

    byte[] buffer = new byte[256];
    using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
    {
        if (fs.Length >= 256)
            fs.Read(buffer, 0, 256);
        else
            fs.Read(buffer, 0, (int)fs.Length);
    }
    try
    {
        System.UInt32 mimetype;
        FindMimeFromData(0, null, buffer, 256, null, 0, out mimetype, 0);
        System.IntPtr mimeTypePtr = new IntPtr(mimetype);
        string mime = Marshal.PtrToStringUni(mimeTypePtr);
        Marshal.FreeCoTaskMem(mimeTypePtr);
        return mime;
    }
    catch (Exception e)
    {
        return "unknown/unknown";
    }
}
}

From inside the Winista method, I fall back on the URLMon here:

   public MimeType GetMimeTypeFromFile(string filePath)
    {
        sbyte[] fileData = null;
        using (FileStream srcFile = new FileStream(filePath, FileMode.Open, FileAccess.Read))
        {
            byte[] data = new byte[srcFile.Length];
            srcFile.Read(data, 0, (Int32)srcFile.Length);
            fileData = Winista.Mime.SupportUtil.ToSByteArray(data);
        }

        MimeType oMimeType = GetMimeType(fileData);
        if (oMimeType != null) return oMimeType;

        //We haven't found the file using Magic (eg a text/plain file)
        //so instead use URLMon to try and get the files format
        Winista.MimeDetect.URLMONMimeDetect.urlmonMimeDetect urlmonMimeDetect = new Winista.MimeDetect.URLMONMimeDetect.urlmonMimeDetect();
        string urlmonMimeType = urlmonMimeDetect.GetMimeFromFile(filePath);
        if (!string.IsNullOrEmpty(urlmonMimeType))
        {
            foreach (MimeType mimeType in types)
            {
                if (mimeType.Name == urlmonMimeType)
                {
                    return mimeType;
                }
            }
        }

        return oMimeType;
    }

Update:

To work out more files using magic here is a FILE SIGNATURES TABLE

Jeremy Thompson
  • 61,933
  • 36
  • 195
  • 321
  • Its a .Net port from a old Java project, I couldn't find info it, not sure if its still around. – Jeremy Thompson Sep 16 '12 at 08:19
  • i am unable to download the `winista` any other source when I can get it ? – Nad Jul 25 '19 at 06:48
  • i am getting error even after loading file at this line `if (!File.Exists(filename))` why ? – Nad Jul 25 '19 at 07:00
  • @BN I uploaded a version of Winista to my mirror. See edit.Or my GitHub here https://github.com/MeaningOfLights/MimeDetect – Jeremy Thompson Jul 25 '19 at 07:06
  • This isn't the way Stackoverflow works, take a step back and put yourself in my shoes, you're getting the error file doesn't exist and I'm supposed to be able to fix it? – Jeremy Thompson Jul 25 '19 at 07:14
  • i am not telling you fix it mate. I just want your help in fixing this issues. I have already implemented your code but while uploading it i am getting the mentioned error. So i was asking you what might be the cause of it. – Nad Jul 25 '19 at 07:19
  • You dont provide any info? First you can't download the project, then its File.Exist throws an error? What path are you using a relative, mobile phone or UNC path? Does the file exist? How are you calling it? Do you **save to local before processing it** or are you trying to processed it via a stream? – Jeremy Thompson Jul 25 '19 at 07:21
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/196961/discussion-between-b-n-and-jeremy-thompson). – Nad Jul 25 '19 at 07:23
  • i am not saving the file before processing it. i am using your code for doing it. I am just storing the path in the database. – Nad Jul 25 '19 at 07:26
  • Just save the uploaded file on the server and detect it's mime type. I don't understand what storing a path in a db has to do with it but comments are for clarification, not asking people to help you get it working. If I had to help people on answers I've already spent hours providing it makes me never want to answer another comment again - ask a new question. https://meta.stackoverflow.com/q/284236/495455 – Jeremy Thompson Jul 25 '19 at 08:01
  • no issue mate, I just upvoted your answer and got the solution for it. Thanks a lot – Nad Jul 25 '19 at 09:29
-1

Checking the names or extension is in no way a reliable idea. The only way you can be sure is that you actually read the content of the file.

i.e. if you want to check the file for image, you should try loading image from the file and if it fails, you can be sure that it is not an image file. This can be done easily using GDI objects.

Same is also true for PDF files.

Conclusion is, don't rely on the user supplied name or extension.

Murtuza Kabul
  • 6,438
  • 6
  • 27
  • 34
  • 2
    Loading the files can potentially be a problem, if you load the whole file and wait for an exception to crash or something. Because thats exactly how some hackers work. They produce a "malformed file" and upload it with the purpose of making the receiver break and if the file is constructed correctly, it might generate a buffer overflow/overrun, that makes the server (by forced mistake) run the actual code placed in the file. I dont say this is "normal", I just say that this is ONE of the ways hackers works. So I would only load a small part of the file and check for header information first. – BerggreenDK Mar 16 '13 at 13:46
-2

you can check you file type in FileApload by

ValidationExpression="^.+.(([pP][dD][fF])|([jJ][pP][gG])|([pP][nN][gG])))$"

for ex: you can add ([rR][aA][rR]) for Rar file type and etc ...

Sajjad mc
  • 75
  • 1
  • 1