Developer forum

Forum » Feature requests » File manager settings: upload extension blacklist

File manager settings: upload extension blacklist

Peter Leleulya
Peter Leleulya
Reply

Hi guys,

I was wondering if it would make sense to be able to blacklist certain file types of being able to be uploaded by a non administrator back-end account to the Files directory.

From a pen-test we got as feedback that we need to exclude for example .exe and .svg files from the files which backend users can upload, because they can do harm to the system.

In my honest opinion I think it is a bit paranoid, but our customer has to comply due to strict rules from their mother company in the USA.

We created, as a workaround, a custom service which monitors the files directory and quarantines these files when they are uploaded (moved and renamed with a timestamp to a quarintine directory in the App_Data folder and log a fatal), but for the back-end user this is not always clear. They try to upload an SVG for example, the system says 'Upload done' and it isn't there ...

Isn't it possible to supply an option in the Files manager settings where an Administrator can blacklist extensions and the File Manger don't show these items and prevent them from being uploaded. Perhaps with a notification to the filemanager about which extensions are excuded by the admin, when extensions are added to the blacklist.


Replies

 
Nicolai Pedersen
Reply

Hi Peter

We had that in the old days and it was nothing but trouble. It is not a feature for DW currently.

Anyways - you can limit whatever you want related to files using web.config - no reason to do custom services etc. There is no harm in uploading exe files - you just have to make sure they cannot execute - that is Windows and IIS permissions.

BR Nicolai

 
Hans Kloppenborg
Reply

Hi Nicolai,

For .exe files it is no problem, issue with their problems with .svg files is that we use these ourselves for instance as logo. So we cannot totally block svg's, but for compliance with the pentest we need to prevent them from being uploaded. 

To be honest I do not think it would be easy to make a standard solution for this specific case. 

Greets Hans

 
Nicolai Pedersen
Reply

Then change the logo to another format or make it inline as SVG: https://css-tricks.com/inline-svg-cached/

Svg is just a text file, it makes no harm. It makes no sense to allow them to be served from the webserver but not allow to upload... Pentest people or not.

You can also make a notification subscriber that will do something if someone uploads svg files.

 
Nicolai Pedersen
Reply

If you do not allow svg - remember to not allow css, html, cshtml, js. They can be used for the same 'bad' things as svg.

 
Nicolai Pedersen
Reply
This post has been marked as an answer

You can do something like this:

 

namespace Dynamicweb.Examples.Notifications.Standard
{
    [Dynamicweb.Extensibility.Notifications.Subscribe(Dynamicweb.Notifications.Standard.Application.BeforeBeginRequest)]
    public class ApplicationBeginRequestObserver : Dynamicweb.Extensibility.Notifications.NotificationSubscriber
    {
        public override void OnNotify(string notification, Dynamicweb.Extensibility.Notifications.NotificationArgs args)
        {
            if (args == null)
                return;

            if (!(args is Dynamicweb.Notifications.Standard.Application.BeforeBeginRequestArgs))
                return;

            Dynamicweb.Notifications.Standard.Application.BeforeBeginRequestArgs item = (Dynamicweb.Notifications.Standard.Application.BeforeBeginRequestArgs)args;
            System.Web.HttpApplication app = (System.Web.HttpApplication)item.sender;

            if (app.Context.Request.Cookies == null || app.Context.Request.Cookies.Count == 0)
                return;

            if (app.Context.Request.HttpMethod.Equals("POST", System.StringComparison.InvariantCultureIgnoreCase) && app.Context.Request?.Files?.Count > 0)
            {
                foreach (string fileName in app.Context.Request?.Files)
                {
                    System.Collections.Generic.List<string> notAllowedExtensions = new System.Collections.Generic.List<string>();
                    notAllowedExtensions.Add(".svg");
                    notAllowedExtensions.Add(".js");

                    System.Web.HttpPostedFile file = app.Context.Request.Files[fileName];
                    foreach (string extension in notAllowedExtensions)
                    {
                        if (file.FileName.EndsWith(extension, System.StringComparison.OrdinalIgnoreCase))
                        {
                            throw new System.Exception($"upload of {extension} is not allowed");
                        }
                    }
                }
            }

            

        }
    }
}

Votes for this answer: 2
 
Peter Leleulya
Peter Leleulya
Reply

Thank you for your extensive and clear explanation on this subject

 
Hans Kloppenborg
Reply

Hi Nicolai,

Thanks for the example. With a bit of refactoring we tested it in our solution, and it prevented the uploads as required! Only point of improvement would be that the exception we throw is shown as an "Unhandled error" in stead of the "not allowed" message.

Our refactored code for people who would like to implement this is as follows:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
 
namespace Application.CustomCode.Observers
{
    [Dynamicweb.Extensibility.Notifications.Subscribe(Dynamicweb.Notifications.Standard.Application.BeforeBeginRequest)]
    public class ApplicationBeginRequestObserver : Dynamicweb.Extensibility.Notifications.NotificationSubscriber
    {
        private readonly List<string> notAllowedExtensions = new List<string> { ".svg"".js"".exe" };
        public override void OnNotify(string notification, Dynamicweb.Extensibility.Notifications.NotificationArgs args)
        {
            if (args == null)
                return;
 
            if (!(args is Dynamicweb.Notifications.Standard.Application.BeforeBeginRequestArgs item))
                return;
 
            var app = (HttpApplication)item.EventSender;
 
            if (app.Context.Request.Cookies == null || app.Context.Request.Cookies.Count == 0)
                return;
 
            if (app.Context.Request.HttpMethod.Equals("POST"StringComparison.InvariantCultureIgnoreCase) && app.Context.Request?.Files?.Count > 0)
            {
 
                var illegalExtensionFileNames = app.Context.Request.Files.AllKeys.Select(key => app.Context.Request.Files[key].FileName).
                                                Where(filename => notAllowedExtensions.Contains(Path.GetExtension(filename), StringComparer.InvariantCultureIgnoreCase));
                if (illegalExtensionFileNames.Any())
                {
                    throw new Exception($"upload of the file(s) {string.Join(", "illegalExtensionFileNames)} is not allowed");
                }
            }
        }
 
        public override bool Equals(object obj)
        {
            if (ReferenceEquals(thisobj))
            {
                return true;
            }
 
            if (obj is null)
            {
                return false;
            }
 
            return false;
        }
 
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
 
        public static bool operator ==(ApplicationBeginRequestObserver leftApplicationBeginRequestObserver right)
        {
            if (left is null)
            {
                return right is null;
            }
 
            return left.Equals(right);
        }
 
        public static bool operator !=(ApplicationBeginRequestObserver leftApplicationBeginRequestObserver right)
        {
            return !(left == right);
        }
 
        public static bool operator <(ApplicationBeginRequestObserver leftApplicationBeginRequestObserver right)
        {
            return left is null ? right is object : left.CompareTo(right) < 0;
        }
 
        public static bool operator <=(ApplicationBeginRequestObserver leftApplicationBeginRequestObserver right)
        {
            return left is null || left.CompareTo(right) <= 0;
        }
 
        public static bool operator >(ApplicationBeginRequestObserver leftApplicationBeginRequestObserver right)
        {
            return left is object && left.CompareTo(right) > 0;
        }
 
        public static bool operator >=(ApplicationBeginRequestObserver leftApplicationBeginRequestObserver right)
        {
            return left is null ? right is null : left.CompareTo(right) >= 0;
        }
    }
}