You’re indubitably familiar with various php scripts that accept an image, and bounding box as parameters, it then resizes the image to fit within the bounding box, returning the output. phpThumb seems to be a popular option.

These scripts tend to be incredibly helpful for sites where the designers change layouts with any frequency, and a large pool of existing images would need to be resized for every modification. I’ve implemented various thumbnailers in the past for just this reason. Generally some measure of caching is implemented so that the first request against a given image, with a given size is stored for future use.

The vulnerability most of these scripts present is the ability of an attacker to manipulate the width and height parameters to force the server to generate an incredibly large number of images. Servers cache based on the requested output size, so it’s easy to step through 1 pixel increments to occupy the servers time, and fill up the cache. A single 1024x768 image can be requested 786,432 times and require resizing each time (1x1, 1x2, 1x3, 1x4, etc.). Your webserver has a finite number of workers available to service incoming requests. When all the workers are occupied new requests are either ignored, or forced to wait for a worker to become ready. A sufficient number of concurrent requests can be an effective Denial of Service attack against the server

Most of the popular scripts are also willing to return an image larger than the original, generally by surrounding it in a black or white bounding box, rather than actually upscaling the image. While this compresses remarkably well, if your source image is 120KB it takes only 8,738 cached requests to fill a gigabyte of disk space (assuming perfect compression on the bounding box). A full hard disk on a single volume machine is disastrous. While not quite as bad on a multi-volume configured system, it still prevents any further images from being cached, scripts also tend to handle failed saves poorly.

Attackers now have two Denial of Service attacks to exploit simultaneously: occupying all your workers with resizing tasks, and filling your hard disk. Sad Times.

The solution is to prevent users from requesting arbitrary versions of your image, by either hard-coding valid sizes into your thumbnailing script (e.g. an array of valid sizes used as a white list), or implement a hashing scheme to prevent attackers from making changes. Several of the popular thumbnailers offer one or both of those options, however I haven’t seen either implemented on any of the production sites I found while researching this post.

If you decide to list valid resize options, and would rather your design team not hate you: Allow arbitrary sizes in development, but watermark the image if it’s not on the whitelist of sizes. A constant reminder that it’s not yet production ready, but wont slow them down while they’re experimenting.

Comments »

No Trackbacks
Ciao, the link to phpThumb is wrong.
#1 Luca on 2011-01-04 10:03 (Reply)

Thanks for the heads up, fixed.
#2 Paul Reinheimer (Homepage) on 2011-01-04 15:40 (Reply)

Hi all..

I actually, take another approach to this problem..

I do all the resizing, cropping etc etc in the backoffice when users upload their pictures, this way I always have control over each image, and it's impossible to have a DoS attack trough the thumb script, I gain a little speed on the frontend by not doing the re-size on the fly and I don't have to worry about caching images as well..

You touch an important point, if the designer changes the images dimensions, that's where I fail, since I don't store the original image, but If if stored it would be as easy as just run a cycle with the images I need to re-size and all done..

But good post anyway..
#3 Tio (Homepage) on 2011-01-04 20:45 (Reply)

The places I've used them have had large libraries of images (thousands), and would run multiple page designs at once, where a new design could involve a few new sizes. These images only existed on the server in a easily available place, so running there on demand seemed easiest.

For larger files like movies, we generally went with your approach, as the webservers were far to busy to start encoding those :-).
#4 Paul Reinheimer (Homepage) on 2011-01-04 20:55 (Reply)

Hi Paul..

The majority of sites that I work on, have around about 200 images.. never more than that..

You made a good point, if for one type of document I have 6 or 7 different sizes to show the image, I could make the backoffice, create every image, but it really doesn't make any sense.. with your way it would be a lot better.. and of course if one of the images changed, that would give a lot of trouble.. and with that quantity of images..

With movies, I would say to play it inside a flash container, and then re-dimension the flash player to every size needed.. For me this would be the best approach..

Stay well..
#5 Tio on 2011-01-06 23:25 (Reply)

Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.
Standard emoticons like :-) and ;-) are converted to images.

Hi, I’m Paul Reinheimer, a developer working on the web.

I co-founded WonderProxy which provides access to over 200 proxies around the world to enable testing of geoip sensitive applications. We've since expanded to offer more granular tooling through Where's it Up

My hobbies are cycling, photography, travel, and engaging Allison Moore in intelligent discourse. I frequently write about PHP and other related technologies.