London Dev Meetup Rescheduled! Due to unavoidable reasons, the event has been moved to 21st May. Speakers remain the same—any changes will be communicated. Seats are limited—register here to secure your spot!

K Khan
Sep 26, 2019
  2781
(1 votes)

EPiServer FileUpload element - Allowed extensions check isn't enough

EPiServer Forms FileUpload element provides a property with the name 'Allowed extensions', that enables content editors to allow website users to upload files in the required format. This can be spoofed easily e.g with value PDF only for allowed extension I am allowed to upload pdf files along with Funny-jpg.pdf also (I hope you got what I meant ;) ). It's a High-security risk for the sites that accept files from end-users via EPiServer forms. I have to come up with an immediate solution, hope this will help someone else also.

1 - extend FileUploadElementBlock (I was Lucky as already had an extended element in our code)

public class StyledFileUploadElementBlock : FileUploadElementBlock
    {
        public override string Validators
        {
            get
            {
                var customValidator = typeof(FileContentTypeCustomValidator).FullName;
                var validators = this.GetPropertyValue(content => content.Validators);
                if (string.IsNullOrEmpty(validators))
                {
                    return customValidator;
                }
                else
                {
                    return string.Concat(validators, EPiServer.Forms.Constants.RecordSeparator, customValidator);
                }
            }
            set
            {
                this.SetPropertyValue(content => content.Validators, value);
            }
        }
    }

2 - Write a service that could look into file signatures and could determine File Type based on the File Contents, not just extension. 

Get file type by signatures

3 - Add your business logic for your custom validator

public class FileContentTypeCustomValidator : ElementValidatorBase
    {
        private Injected<IFileValidationService> _fileService;
        protected IFileValidationService FileValidationService { get { return _fileService.Service; } }

        public override bool? Validate(IElementValidatable targetElement)
        {
            StyledFileUploadElementBlock fileUploadElementBlock = targetElement as StyledFileUploadElementBlock;
            if (fileUploadElementBlock == null)
                return true;
            var files = targetElement?.GetSubmittedValue();
            if (files == null)
                return true;
            var postedFiles = files as List<HttpPostedFile>;
            if (postedFiles != null && postedFiles.Any())
            {
                foreach (var httpPostedFile in postedFiles)
                {
//Your Business logic
                    var fileType = FileValidationService.GetFileType(httpPostedFile.InputStream);
                    if (string.IsNullOrEmpty(fileType.Extension))
                        return false;

                    if (!fileUploadElementBlock.FileExtensions.Contains(fileType.Extension))
                    {
                        return false;
                    }
                }
            }

            return true;
        }

        public override bool AvailableInEditView
        {
            get
            {
                return false;
            }
        }

        /// 
        public override IValidationModel BuildValidationModel(IElementValidatable targetElement)
        {
            StyledFileUploadElementBlock fileUploadElementBlock = targetElement as StyledFileUploadElementBlock;
            if (fileUploadElementBlock == null)
            {
                return base.BuildValidationModel(targetElement);
            }

            var fileExtensions = fileUploadElementBlock.FileExtensions;
            if (base._model != null) return base._model;

            string validatorMessage = base._validationService.Service.GetValidatorMessage(base.GetType(), (fileExtensions.Split(new string[1]
            {
                ","
            }, StringSplitOptions.RemoveEmptyEntries).Length != 0) ? "allowedextensionsmessage" : string.Empty);
            base._model = new AllowedExtensionsValidationModel
            {
                Accept = fileExtensions,
                Message = string.Format(validatorMessage, fileExtensions)
            };

            return base._model;
        }
    }


Stay Safe!

EPiServer Forms version: 4.25.0

Sep 26, 2019

Comments

Please login to comment.
Latest blogs
Understanding the Infrastructure Powering AI Agents for Marketing

The marketing world is increasingly captivated by the potential of AI agents. However, it's crucial to recognize that these agents are not simply...

Patrick Lam | May 15, 2025

Meet the Newest OMVPs – Winter 2025 Cohort

We're excited to officially welcome the latest winter cohort of Optimizely Most Valuable Professionals (OMVPs) - a group of passionate tech...

Satata Satez | May 14, 2025

Helper method to encode query string properly

When using Url.ContentUrl() in Optimizely 12, encodes spaces as + in the query string. If you want to encode the spaces as %20, use the below helpe...

sunylcumar | May 13, 2025

Get ContentReference from GUID

Optimizely CMS 12 provides a Utility function to retrieve Content Reference from a Guid by ussing the below static method. var contentReference =...

sunylcumar | May 13, 2025

Creating a Dropdownlist in Optimizely CMS: Populate ISelectionFactory with values from another block's properties

Create a Block to hold selection options using EPiServer.Cms.Shell.UI.ObjectEditing.EditorDescriptors; using EPiServer.PlugIn; using EPiServer.Shel...

sunylcumar | May 12, 2025

Opal AI available in Optimizely CMS (SaaS)

Use Opal AI to translate your content!

Tomas Hensrud Gulla | May 12, 2025 |