News Archive
PhpRiot Newsletter
Your Email Address:

More information

Thumbnailers: configure with caution

Note: This article was originally published at Planet PHP on 4 January 2011.
Planet PHP

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.