Consider a situation where remote users can upload their own pictures to the site. Lets say that an attacker uploads an image to http://www.example.com/uploads/sample.gif
. What happens, given the server block above, if the attacker then browses to http://www.example.com/uploads/sample.gif/fake.php
?
- nginx will look at the URL, see that it ends in .php, and pass the path along to the PHP fastcgi handler.
- PHP will look at the path, find the
.gif
file in the filesystem, and store /somefilename.php
in $_SERVER['PATH_INFO'], executing the contents of the GIF as PHP.
This issue can be mitigated in a number of ways, but there are downsides associated with each of the possibilities:
- Set
cgi.fix_pathinfo
to false in php.ini
(it’s set to true by default). This change appears to break any software that relies on PATH_INFO being set properly (eg: Wordpress).
- Add
try_files $uri =404;
to the location block in your nginx config. This only works when nginx and the php-fcgi workers are on the same physical server.
- Add a new location block that tries to detect malicious URLs. Unfortunately, detecting based on the URL alone is impossible: files don’t necessarily need to have extensions (eg: README, INSTALL, etc).
- Explicitly exclude upload directories using an if statement in your location block. The disadvantage here is the use of a blacklist: you have to keep updating your nginx configuration every time you install a new application that allows uploads.
- Don’t store uploads on the same server as your PHP. The content is static anyway: serve it up from a separate (sub)domain. Of course, this is easier said than done: not all web applications make this easy to do.