Calling all developers! We invite you to provide your input on Feature Experimentation by completing this brief survey.

 

K Khan
Sep 26, 2019
  2587
(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
Level Up with Optimizely's Newly Relaunched Certifications!

We're thrilled to announce the relaunch of our Optimizely Certifications—designed to help partners, customers, and developers redefine what it mean...

Satata Satez | Jan 14, 2025

Introducing AI Assistance for DBLocalizationProvider

The LocalizationProvider for Optimizely has long been a powerful tool for enhancing the localization capabilities of Optimizely CMS. Designed to ma...

Luc Gosso (MVP) | Jan 14, 2025 | Syndicated blog

Order tabs with drag and drop - Blazor

I have started to play around a little with Blazor and the best way to learn is to reimplement some old stuff for CMS12. So I took a look at my old...

Per Nergård | Jan 14, 2025

Product Recommendations - Common Pitfalls

With the added freedom and flexibility that the release of the self-service widgets feature for Product Recommendations provides you as...

Dylan Walker | Jan 14, 2025

My blog is now running using Optimizely CMS!

It's official! You are currently reading this post on my shiny new Optimizely CMS website.  In the past weeks, I have been quite busy crunching eve...

David Drouin-Prince | Jan 12, 2025 | Syndicated blog

Developer meetup - Manchester, 23rd January

Yes, it's that time of year again where tradition dictates that people reflect on the year gone by and brace themselves for the year ahead, and wha...

Paul Gruffydd | Jan 9, 2025