Search code examples
c#asp.net-coreimage-resizingddosimagesharp

How to prevent ImageSharp Web from resizing to certain sizes?


I am using ImageSharp.Web to resize images on my ASP.NET Core 5.0 website.

To prevent DDoS (Distributed Denial of Service attacks), I would like to restrict the sizes that ImageSharp.Web can resize too.

For example I have an image with an original size of 800x400 (100kb) that I am resizing using the following:

<img src="image.jpg?width=300&height=300" alt="..." /> // image will be 40 kb, bandwidth saved yay!

The problem is if an evil user decides to request the image with:

<img src="image.jpg?width=8000&height=4000" alt="..." /> // 8,000 x 4,000 => image is now 2mb

If that user request this image with 'high-numbered' pixel sizes (7000,7001,7002...8000} say 10,000 times the server will become non-responsive due to memory exhausting and bandwidth usage.

  1. How can I restrict ImageSharp.Web to not resize images above their original size?
  2. How can I restrict ImageSharp.Web to only resize images to e.g. 300x300, and 300x600?

I don't see any configurable options for that in ImageSharp.Web (https://docs.sixlabors.com/articles/imagesharp.web/gettingstarted.html).

My startup.cs:

    public void ConfigureServices(IServiceCollection services)
    {

        // ....

        services.AddImageSharp();

    }

Solution

  • The place your are looking for is actually on that page. It's the options.OnParseCommandsAsync function.

    We actually do some default sanitation to help reduce potential attack vectors (and disallow that specific evil user) but you can implement custom rules you want there instead. Here's the default method.

    https://github.com/SixLabors/ImageSharp.Web/blob/b72064b3b8cb8b883f8310c86b6d7e5643d80ad3/src/ImageSharp.Web/Middleware/ImageSharpMiddlewareOptions.cs#L20-L44

    private Func<ImageCommandContext, Task> onParseCommandsAsync = c => 
    { 
        if (c.Commands.Count == 0) 
        { 
            return Task.CompletedTask; 
        } 
    
        // It's a good idea to have this to provide very basic security. 
        // We can safely use the static resize processor properties. 
        uint width = c.Parser.ParseValue<uint>( 
            c.Commands.GetValueOrDefault(ResizeWebProcessor.Width), 
            c.Culture); 
    
        uint height = c.Parser.ParseValue<uint>( 
            c.Commands.GetValueOrDefault(ResizeWebProcessor.Height), 
            c.Culture); 
    
        if (width > 4000 && height > 4000) 
        { 
            c.Commands.Remove(ResizeWebProcessor.Width); 
            c.Commands.Remove(ResizeWebProcessor.Height); 
        } 
    
        return Task.CompletedTask; 
    };  
    

    However this doesn't allow you to prevent upscaling since we haven't attempted to decode the image at this point so do not know anything about it. You would have to implement your own version of the ResizeWebProcessor class (inheriting should be fine since it's not sealed) and override this method. You can remove the original and register your own as described in the documentation.

    https://github.com/SixLabors/ImageSharp.Web/blob/b72064b3b8cb8b883f8310c86b6d7e5643d80ad3/src/ImageSharp.Web/Processors/ResizeWebProcessor.cs#L69-L84

    public FormattedImage Process( 
         FormattedImage image, 
         ILogger logger, 
         IDictionary<string, string> commands, 
         CommandParser parser, 
         CultureInfo culture) 
    { 
        ResizeOptions options = GetResizeOptions(commands, parser, culture); 
    
        if (options != null) 
        { 
            image.Image.Mutate(x => x.Resize(options)); 
        } 
    
        return image; 
    } 
    

    Hope that makes it clear.