Block files by MIME content type while Sitecore upload

As per Web Security best practices, while media upload in Sitecore, we should block upload of EXE, DLL, BAT, ASPX, ASP, etc. files on server. Do you think, it is enough? I think, No.

We should also block files by checking their MIME content types because someone can also upload Exe/Dll files by renaming them as Jpg or any other extension is allowed. So, this can be a serious threat too.

So, checking MIME content type is equal important as checking file extensions.

Why checking only file extension is not enough?

We implemented a module to restrict certain extensions, provided by Yuriy Yurkovsky from Sitecore Support, Prevent files from being uploaded which is working absolutely fine. Michael Reynolds also nicely presented restricting file extensions on his post Restrict Certain Extensions From Being Uploaded.

Later on, while testing for security threats, we found two issues while implementing blocking extensions.Thanks to our QA Analyst Chirag Patel for finding such nice scenarios and also shown us how it is harmful.
  1. What if I upload file as "setup. EXE" instead of "setup.EXE"? (Just add a space after dot)
  2. What if I upload file my EXE file by renaming as JPG? (Setup.JPG instead of Setup.EXE)
Yes, in both cases we were able to upload EXE contents which should be blocked by us. See below image, how EXE file uploaded as JPG behaves when client requests. This can be a serious threat to our application.

EXE file uploaded as JPG - Security Threat

For case 1, we updated the code given in above module by removing the space between dot and file extension.
For case 2, we can use below approach.

How to restrict upload of certain MIME content types

As per the case 2, users can upload EXE  files by renaming them as JPG file. So, we can block them by their content type. Let's see how we can block content types, which is equal important as blocking files by extensions.

Below can be the patch configuration file, for better understanding, I used same format as Michael Reynolds' post to restrict extensions:

Here, two kind of content types are blocked:
- application/octet-stream (Used for bin, dms, lha, lzh, exe, dll contents)
- application/zip (Used for zip content)
 
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <processors>
      <uiUpload>
        <processor mode="on" type="SitecoreTactics.Pipelines.Upload.CheckForRestrictedContentType, SitecoreTactics" patch:before="processor[@type='Sitecore.Pipelines.Upload.CheckSize, Sitecore.Kernel']">
          <restrictedcontentTypes hint="raw:AddRestrictedContentType">
            <!-- content types to restrict -->
            <contentType>application/octet-stream</contentType>
            <contentType>application/zip</contentType>
        </restrictedcontentTypes>
        </processor>
      </uiUpload>
    </processors>
  </sitecore>
</configuration>

You can get more content types from:
http://www.freeformatter.com/mime-types-list.html
http://www.dailycoding.com/Posts/mime_contenttypes_with_file_extension.aspx


Below can be the source code to block certain content types defined in above config file.
namespace SitecoreTactics.Pipelines.Upload
{
    public class CheckForRestrictedContentType : UploadProcessor
    {
        private List<string> _RestrictedContentType;
        private List<string> RestrictedContentType
        {
            get
            {
                if (_RestrictedContentType == null)
                {
                    _RestrictedContentType = new List<string>();
                }

                return _RestrictedContentType;
            }
        }

        public void Process(UploadArgs args)
        {
            foreach (string fileKey in args.Files)
            {
                string fileName = args.Files[fileKey].FileName;
                string contentType = args.Files[fileKey].ContentType;

                if (IsRestrictedContentType(contentType))
                {
                    args.ErrorText = Translate.Text(string.Format("The file \"{0}\" cannot be uploaded. Files with an content Type of {1} are not allowed.", fileName, contentType));
                    Log.Warn(args.ErrorText, this);
                    args.AbortPipeline();
                }
            }
        }


        private bool IsRestrictedContentType(string contentType)
        {
            return RestrictedContentType.Exists(restrictedContentType => string.Equals(restrictedContentType, contentType, StringComparison.CurrentCultureIgnoreCase));
        }

        protected virtual void AddRestrictedContentType(XmlNode configNode)
        {
            if (configNode == null || string.IsNullOrEmpty(configNode.InnerText))
            {
                return;
            }

            RestrictedContentType.Add(configNode.InnerText);
        }
    }
}

I feel, now my Sitecore application is more secured!

8 comments:

  1. Thanks for the great post! I was looking at Mike's SitecoreJunkie blog to try and implement the MimeType filter. It wasn't exactly what I needed so he pointed me to your site/blog.

    I have two upload filters working, one for file size nd one for file extension, but as you point out and Mike did as well, this just isn't good enough. So, I set out to implement the solution above and just can't seem to get it to work.

    When the page loads the class is entered but it doesn't really do much. Need a second set of eyes to figure out my issue. Is posting code to the comments here a good way to show you what I've done or is there a better avenue to do that?

    thanks!

    ReplyDelete
    Replies
    1. Hi Larry, if you are trying to block by Mime Types, then there are two things you have to consider:
      Sitecore has two types of Uploads available.

      1. Classic (non-Flash) upload -> The above code will work fine which works by identifying MIME types of file being uploaded.

      2. Flash upload -> Flash never gives us MimeType, so above code won't work. For that you can use Magic Numbers. http://en.wikipedia.org/wiki/Magic_number_(programming)

      Each type of media (Mime Type) starts with some fixed characters, which is known as Magic Numbers. You can also check those characters to identify MIME types.

      For Example, a PNG file content starts with "‰PNG"
      PDF file content starts with "%PDF"
      And so on for EXE, MSI, etc. extensions.

      Above link will guide you for this. Still if you have any doubt, you can contact me at: contact@patelyogesh.in

      Delete
    2. Well, it's been almost a year... this little project was put on the back burner but is now my top priority - we have several business uses for it.

      I found in our web.config that our Upload.Classic setting is false, which says to me we are using the Flash upload. Am I correct in believing that? I suppose it's possible that a config patch could override that...

      So, it appears I need to set up my project to check the uploaded file's "magic number". Seems that I'll need to code the C# class to get the magic number from the file and then potentially check it against config entries. I found a site where someone did something similar in ColdFusion although they hardcoded each filetype in the "class" ( http://www.bennadel.com/blog/2490-detecting-file-type-using-magic-numbers-in-coldfusion.htm ).

      Just looking for the best way to do this. Thoughts on this?

      Delete
    3. Hi Larry, I just implemented it locally and sent you some sample code to block file upload using magic numbers. Please have a look into it. I will post it to my blog soon so can be helpful to others!

      Delete
  2. Hi Yogesh.. Great article indeed.. Kudos..:-)
    As Larry was saying.. even i have that requirement to restrict the media by mime types... by default Classic upload is false- we need to go with Flash upload.. if possible can you please share that code snippet what you hav sent to Larry as mentioned in the above comments section..Please..
    Btw.. i Love your blog posts and also i have bought your cookbook.. Awesome work.. please keep uploading new features and if you can post some articles on sitecore 9.. that will be great..:-) Thanks Much

    ReplyDelete
    Replies
    1. Hi Sharath, thank you for reading my blogs and the book. You can find the repo at - https://github.com/patelyogesh-in/MagicNumbers. The magic numbers are hardcoded in the sample, better to keep them our in config file. One more thing - it's not tested on later Sitecore versions, but the logic will remain same.
      Hope this helps!

      Delete