How to stop malicious files being uploaded to Media Library by content type (MIME)

I had the requirement to validate files before uploading into the Sitecore’s Media Library – if its not a item in the decided type, the upload should be blocked and the User should be informed.

So I found out that there is a Sitecore’s Filter tool https://doc.sitecore.com/developers/91/platform-administration-and-architecture/en/secure-the-file-upload-functionality.html

This tool works really nice for checking/filtering the file extensions. But by considering to use this filter i was wondering if this one is enough.

There is one concern. Somebody could rename the e.g .EXE or .BAT file to .PNG and upload it, so this bad intention wouldn’t be covered by this filter.

I peeked into the Sitecore.Kernel.dll and saw there is a prepared class Sitecore.Pipelines.Upload.FilterBlockedExtensions for only validation of extension so I decided write my own Upload Processor.

You can easily use this Processer by downloading from the Sitecore’s Marketplace https://marketplace.sitecore.net/Modules/M/Malicious_Files_Upload_Blocker.aspx

This is the class

I created a FilterBlockedContentType Processor which inherits from Sitecore.Pipelines.Upload.UploadProcessor and compares the file’s content type with the blacklisted types in the configuration when it is getting executed.

If the uploading file is of the same mime type, the user gets informed and the pipeline gets aborted.

/// <summary>
    /// Cancel file uploading if content type is marked as disabled to be uploaded
    /// </summary>
    public class FilterBlockedContentType : UploadProcessor
    {

        private readonly List<string> _filteredContentTypes = new List<string>();

        /// <summary>
        /// Add the blacklisted content types
        /// </summary>
        /// <param name="configNode"></param>
        protected virtual void AddRestrictedContentType(XmlNode configNode)
        {
            if (configNode == null)
            {
                return;
            }

            var contentTypes = configNode.InnerText.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
            foreach (var types in contentTypes)
                _filteredContentTypes.Add(types);
        }

        private bool IsFilteredContentType(string contentType)
        {
            return _filteredContentTypes.Exists(type =>
                string.Equals(type, contentType, StringComparison.CurrentCultureIgnoreCase));

        }

        /// <summary>
        /// Runs the processor
        /// </summary>
        /// <param name="args"></param>
        public void Process(UploadArgs args)
        {
            foreach (string fileKey in args.Files)
            {
                var fileName = args.Files[fileKey]?.FileName;
                var contentType = args.Files[fileKey]?.ContentType;

                if (IsFilteredContentType(contentType))
                {
                    var file = StringUtil.EscapeJavascriptString(fileName);
                    var reason = StringUtil.EscapeJavascriptString("File upload is restricted.");

                    args.UiResponseHandlerEx.FileCannotBeUploaded(file, reason);

                    args.ErrorText = Translate.Text($"The file \"{fileName}\" cannot be uploaded");
                    Log.Error(args.ErrorText, this);
                    args.AbortPipeline();
                    break;
                }


            }
        }

    }

Patching the configuration

In order to get this Processor patched and placed/exectuted first I used this directive patch:before=”*[1]”

In the <contentType> node you can block multiple mime types divided by a semicolon (;)

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/">
  <sitecore role:require="Standalone or ContentManagement">
    <processors>
    <uiUpload>
      <processor mode="on" patch:before="*[1]" type="JobMarket.Foundation.SitecoreExtensions.Pipelines.FilterBlockedContentType, JobMarket.Foundation.SitecoreExtensions">
        <restrictedContentType hint="raw:AddRestrictedContentType">
          <contentType>application/octet-stream</contentType>
        </restrictedContentType>
      </processor>
    </uiUpload>
    </processors>
  </sitecore>
</configuration>

Content type application/octet-stream is the type for all executable files

Result

If this file is one of the configured filtered/blocked content types, the upload will not be started and the user gets the response for aborting the process.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s