4
3
It took several hours to find out how to properly configure NginX
, but I still think I might have missed something. Mainly because this perfectly working setup raises more questions than it answers. Perhaps this even is an NginX
-bug or something introduced by Debian
in Version: 1.2.1-2.2+wheezy2
of Package: nginx-extras
, I simply do not know.
Please note that my example already is stripped down to the bare minimum (so take this as a starting point) but it still shall contain all necessary current secure fixes.
Please note that I dislike error prone heuristics. Therefor this runs with /etc/php/fpm/pool.d/www.conf
set such, that php-fpm
takes the script directly from PATH_TRANSLATED
instead of guessing it:
php_admin_value[cgi.fix_pathinfo]=0
security.limit_extensions = .php
php_admin_flag[expose_php] = off
Here is the php
-file /home/tino/www/index.php
which dumps the variables:
<?
header("content-type: text/plain");
$a = array("PATH_TRANSLATED", "SCRIPT_FILENAME", "DOCUMENT_URI", "PATH_INFO", "QUERY_STRING" );
foreach ($a as &$v)
printf("%-15s %s\n", $v, $_SERVER[$v]);
?>
Working NginX configuration
Note that /home/tino/www
is where my test script lives. And you possibly want to populate all the other params from /etc/nginx/fastcgi_params
. For example you need
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
to populate PHP_SELF
.
server_tokens off;
server {
listen 80;
root /home/tino/www;
if ($request_uri ~ " ") { return 444; }
location ~ [^/]\.php(/|$) {
limit_except GET HEAD POST { deny all; }
fastcgi_split_path_info ^((?U).+\.php)(.*)$;
try_files $fastcgi_script_name =404;
set $wtf $fastcgi_path_info;
fastcgi_param PATH_INFO $wtf;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
}
}
This gives me following output for http://example.com/index.php/a.php?b=b.php
PATH_TRANSLATED /home/tino/www/index.php
SCRIPT_FILENAME /home/tino/www/index.php
DOCUMENT_URI /index.php
PATH_INFO /a.php
QUERY_STRING b=b.php
This is exactly what I want. Note that this works for less problematic URIs too, of course.
The not working config
However, the straight forward configuration does not work, and I am really puzzled, why:
server_tokens off;
server {
listen 80;
root /home/tino/www;
if ($request_uri ~ " ") { return 444; }
location ~ [^/]\.php(/|$) {
limit_except GET HEAD POST { deny all; }
fastcgi_split_path_info ^((?U).+\.php)(.*)$;
try_files $fastcgi_script_name =404;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
}
}
This is the same as above, just the $wtf
workaround is missing:
set $wtf $fastcgi_path_info;
fastcgi_param PATH_INFO $wtf;
became
fastcgi_param PATH_INFO $fastcgi_path_info;
But this does not work, output for http://example.com/index.php/a.php?b=b.php
now is:
PATH_TRANSLATED /home/tino/www/index.php
SCRIPT_FILENAME /home/tino/www/index.php
DOCUMENT_URI /index.php
PATH_INFO
QUERY_STRING b=b.php
As you can see: PATH_INFO
vanished. This has nothing to do with php-fpm
, it's purely an NginX
thing!
Insecure config works again
Following configuration, which opens a major security hole due to the missing file check, works again:
server_tokens off;
server {
listen 80;
root /home/tino/www;
if ($request_uri ~ " ") { return 444; }
location ~ [^/]\.php(/|$) {
limit_except GET HEAD POST { deny all; }
fastcgi_split_path_info ^((?U).+\.php)(.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
}
}
It has a little bit different outcome on http://example.com/index.php/a.php?b=b.php
though (SCRIPT_FILENAME
looks wrong, DOCUMENT_URI
maybe correct from a different point of view).
PATH_TRANSLATED /home/tino/www/index.php
SCRIPT_FILENAME /home/tino/www/index.php/a.php
DOCUMENT_URI /index.php/a.php
PATH_INFO /a.php
QUERY_STRING b=b.php
So please
Apparently try_files
breaks how $fastcgi_path_info
is parsed after setting the regexp with fastcgi_split_path_info
.
So, please, can anybody tell me, if this $wtf
workaround is indeed the correct solution or do I still have to worry about additional bad sideffects of try_files
?
Thanks. (If I missed some important security bit, please comment.)
Note that the tags are perhaps a bit misleading. This question is "how to correctly (and securely) calculate $fastcgi_path_info in NginX" to stuff it into
PATH_INFO
and not "how to put this correctly into params such thatfpm
sees it in PATH_INFO correctly". Sorry for that disturbance. – Tino – 2014-02-28T19:01:28.337