There has been a lot of talking about a security issue relative to the cgi.fix_pathinfo
PHP option used with Nginx (usually PHP-FPM, fast CGI).
As a result, the default nginx configuration file used to say:
# NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
However, now, the "official" Nginx wiki states that PATH_INFO can be handled correctly without disabling the above PHP option. So what?
Questions
- Can you explain clearly what does
cgi.fix_pathinfo
do? (official doc just says: "For more information on PATH_INFO, see the CGI specs") - What will PHP really do with these
PATH_INFO
andSCRIPT_FILENAME
variables? - Why and how can it be dangerous with Nginx? (detailed examples)
- Does the issue still exist in recent versions of these programs?
- Is Apache vulnerable?
I'm trying to understand the issue at each step. For example, I don't understand why using the php-fpm Unix socket could avoid this problem.
Best Answer
TL;DR - the fix (which you may not even need) is VERY SIMPLE and at the end of this answer.
I'll try to address your specific questions, but your misunderstanding of what PATH_INFO is makes the questions themselves a little bit wrong.
First question should be "What is this path info business?"
Path info is stuff after the script in a URI (should start with a forward slash, but ends before the query arguments, which start with a
?
). The last paragraph in the overview section of the Wikipedia article about CGI sums it up nicely. Below thePATH_INFO
is "/THIS/IS/PATH/INFO":http://example.com/path/to/script.php/THIS/IS/PATH/INFO?query_args=foo
Your next question should have been: "How does PHP determine what
PATH_INFO
andSCRIPT_FILENAME
are?"PATH_INFO
, so what was supposed to bePATH_INFO
was munged ontoSCRIPT_FILENAME
which, yes, is broken in many cases. I don't have an old enough version of PHP to test with, but I believe it sawSCRIPT_FILENAME
as the whole shebang: "/path/to/script.php/THIS/IS/PATH/INFO" in the above example (prefixed with the docroot as usual).PATH_INFO
andSCRIPT_FILENAME
gets just the part that points to the script being requested (prefixed with the docroot of course).PATH_INFO
, they had to add a configuration setting for the new feature so people running scripts that depended on the old behavior could run new PHP versions. That's why there's even a configuration switch for it. It should have been built-in (with the "dangerous" behavior) from the start.But how does PHP know what part is the script and what it path info? What if the URI is something like:
http://example.com/path/to/script.php/THIS/IS/PATH/INFO.php?q=foo
SCRIPT_FILENAME
has been determined andPATH_INFO
gets the rest.SCRIPT_FILENAME
gets "/foo.jpg" (again, prefixed with docroot) andPATH_INFO
gets "/nonexistent.php".Why and how it can be dangerous should now be clear:
Nginx and Apache could be built or configured to prevent requests using this trickery, and there are plenty of examples for how to do that, including in user2372674's answer. This blog article explains the problem nicely, but it's missing the right solution.
However, the best solution is to just make sure PHP-FPM is configured correctly so that it will never execute a file unless it ends with ".php". It's worth noting that recent versions of PHP-FPM (~5.3.9+?) have this as default, so this danger isn't so much problem any more.
The Solution
If you have a recent version of PHP-FPM (~5.3.9+?), then you need to do nothing, as the safe behaviour below is already the default.
Otherwise, find php-fpm's
www.conf
file (maybe/etc/php-fpm.d/www.conf
, depends on your system). Make sure you have this:Again, that's default in many places these days.
Note that this doesn't prevent an attacker from uploading a ".php" file to a WordPress uploads folder and executing that using the same technique. You still need to have good security for your applications.