Bug #68053 [Opn->Wfx]: PHP-FPM with cgi.fix_pathinfo 0 loads script from PATH_TRANSLATED
| From: | bukka@php.net | Date: | Thu, 06 Apr 2023 14:41:13 +0000 |
| Subject: | Bug #68053 [Opn->Wfx]: PHP-FPM with cgi.fix_pathinfo 0 loads script from PATH_TRANSLATED | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-244126@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=68053&edit=1
ID: 68053
Updated by: bukka@php.net
Reported by: devel at jasonwoods dot me dot uk
Summary: PHP-FPM with cgi.fix_pathinfo 0 loads script from
PATH_TRANSLATED
-Status: Open
+Status: Wont fix
Type: Bug
Package: FPM related
Operating System: CentOS 6.5
PHP Version: 5.5.17
-Assigned To:
+Assigned To: bukka
Block user comment: N
Private report: N
New Comment:
I have been looking into this and agree that the behaviour is a bit unfortunate. However I
don't think we can fix it all at this stage as it could result in hard to find a BC break as
some application might rely on the PATH_TRANSLATED being used and PHP_SELF having always PATH_INFO
value if set. I don't think we can fix the PATH_TRANSLATED at all and don't see it as a
big issue as there is still cgi.discard_path = 1. There is a better case for PHP_SELF though and I
think we should address it as an improvement so we limit the impact of its BC break. For that I
created following issue: https://github.com/php/php-src/issues/11025
Closing this as won't fix even though the PHP_SELF will be likely addressed but that's
just part of this report and will be more an improvement as I said.
Previous Comments:
------------------------------------------------------------------------
[2021-08-03 12:22:07] cmb@php.net
Related To: Bug #67164
------------------------------------------------------------------------
[2014-09-19 10:45:45] devel at jasonwoods dot me dot uk
Originally raised as #67164 but was private, so we can delete/close/duplicate #67164 and keep this
public one - I'm keen if anyone else experience this or knows what is "right"
------------------------------------------------------------------------
[2014-09-19 10:44:32] devel at jasonwoods dot me dot uk
Description:
------------
Looking at the nginx example config here:
http://wiki.nginx.org/HttpFcgiModule#fastcgi_split_path_info
(or even here: http://wiki.nginx.org/PHPFcgiExample)
During a request, PATH_TRANSLATED is set to the full path to the PATH_INFO on the filesystem as
defined by the CGI specification: http://www.ietf.org/rfc/rfc3875
Now we have something like this:
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^((?U).*[^/]\.php)(/.*)$;
include "fastcgi.conf"; # To get the other standard variables
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
if (!-f $document_root$fastcgi_script_name) {
return 404;
}
fastcgi_pass unix:/var/run/php-fpm/{{ id }}.sock;
}
This works OK with cgi.fix_pathinfo=1 in the PHP-FPM configuration. Scripts run fine as expected
with PATH_INFO populated and PATH_TRANSLATED populated. For example, requesting
www.test.com/script.php/images would load script.php.
Now, a lot of blogs (maybe incorrectly) say to disable cgi.fix_pathinfo for security, and reading
the docs it makes sense... I've done the splitting in Nginx, why should FPM do any... However,
setting it to 0 will generally result in "Access is denied!" and error_log such as the
following:
FastCGI sent in stderr: "Access to the script '<root>/images' has been denied
(see security.limit_extensions)" while reading response header from upstream, client: X.X.X.X,
server: www.test.com, request: "GET /test.php/images HTTP/1.1", upstream:
"fastcgi://unix:/var/run/php-fpm/test.sock:", host: "www.test.com"
If you change the request to www.test.com/script.php/images/anotherphpscript.php, and actually
create that script in <root>/images/anotherphpscript.php, it actually loads that script! It
seems that when PATH_TRANSLATED is present and fix_pathinfo is 0, PHP loads the script from the path
pointed to by PATH_TRANSLATED and ignores SCRIPT_FILENAME completely! Yet from what I can gather,
PATH_TRANSLATED is the filesystem path to the PATH_INFO stem - this is not meant to be the script to
run!
Looking into it further though, it seems PHP documentation kind of states this:
http://php.net/manual/en/reserved.variables.server.php
'PATH_TRANSLATED' - Filesystem- (not document root-) based path to the current script,
after the server has done any virtual-to-real mapping.
Yet looking elsewhere you get a completely different definition:
http://oreilly.com/openbook/cgi/ch02_04.html
Meanwhile, the variable PATH_TRANSLATED is also set, which maps the information stored in PATH_INFO
to the document root directory (e.g., /usr/local/etc/httpd/ public/cgi/cgi-doc.txt).
Have I misunderstood this completely or PHP completely loading the wrong script?
The thing that concerns me is it appears that using configs on the Nginx website and following a
common security recommendation on the web, essentially makes one potentially INSECURE, as it means
someone could run a PHP file in /images/ even if you have a match in nginx on /images/ that returns
401
FYI - Adding cgi.discard_path = 1 (with cgi.fix_pathinfo = 0) seems to fix the problem though
appears to be sparsely mentioned, but introduces a new issue in that PHP_SELF remains the same and
ends up the PATH_INFO (/images/anotherphpscript.php - which would be right if it was still running
that script)
Compare to cgi.discard_path = 0 (default) and cgi.fix_pathinfo = 1 where PHP_SELF is correct
(/script.php/images/anotherphpscript.php)
Test script:
---------------
This is a really good example, who
Setup nginx with php-fpm and use following block for requests:
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^((?U).*[^/]\.php)(/.*)$;
include "fastcgi.conf"; # To get the other standard variables
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
if (!-f $document_root$fastcgi_script_name) {
return 404;
}
fastcgi_pass unix:/var/run/php-fpm/{{ id }}.sock;
}
1. Create <root>/images/anotherphpscript.php
<?php
echo "ANOTHERPHPSCRIPT.PHP";
phpinfo();
?>
2. Create <root>/script.php to output "SCRIPT.PHP"
<?php
echo "SCRIPT.PHP";
?>
3. Request www.test.com/script.php/images/anotherphpscript.php
Expected result:
----------------
When requesting www.test.com/script.php/images/anotherphpscript.php
Receive output "SCRIPT.PHP"
Actual result:
--------------
When requesting www.test.com/script.php/images/anotherphpscript.php
Receive output "ANOTHERPHPSCRIPT.PHP"
Receive PHP info dump with following _SERVER:
_SERVER["USER"] test
_SERVER["HOME"] /home/test
_SERVER["FCGI_ROLE"] RESPONDER
_SERVER["SCRIPT_FILENAME"] /home/access/site/script.php
_SERVER["QUERY_STRING"] no value
_SERVER["REQUEST_METHOD"] GET
_SERVER["CONTENT_TYPE"] no value
_SERVER["CONTENT_LENGTH"] no value
_SERVER["SCRIPT_NAME"] /script.php
_SERVER["REQUEST_URI"] /script.php/images/anotherphpscript.php
_SERVER["DOCUMENT_URI"] /script.php/images/anotherphpscript.php
_SERVER["DOCUMENT_ROOT"] /home/access/site
_SERVER["SERVER_PROTOCOL"] HTTP/1.1
_SERVER["GATEWAY_INTERFACE"] CGI/1.1
_SERVER["SERVER_SOFTWARE"] nginx/1.6.0
_SERVER["REMOTE_ADDR"] X.X.X.X
_SERVER["REMOTE_PORT"] XXXXX
_SERVER["SERVER_ADDR"] X.X.X.X
_SERVER["SERVER_PORT"] 80
_SERVER["SERVER_NAME"] www.test.com
_SERVER["REDIRECT_STATUS"] 200
_SERVER["PATH_INFO"] /images/anotherphpscript.php
_SERVER["HTTPS"] no value
_SERVER["HTTP_X_FORWARDED_FOR"] X.X.X.X
_SERVER["PATH_TRANSLATED"] /home/access/site/images/anotherphpscript.php
_SERVER["HTTP_HOST"] www.test.com
_SERVER["HTTP_DNT"] 1
_SERVER["HTTP_COOKIE"] no value
_SERVER["HTTP_CONNECTION"] keep-alive
_SERVER["HTTP_ACCEPT"] text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
_SERVER["HTTP_USER_AGENT"] Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2)
AppleWebKit/537.75.14 (KHTML, like Gecko) Version/7.0.3 Safari/537.75.14
_SERVER["HTTP_ACCEPT_LANGUAGE"] en-us
_SERVER["HTTP_ACCEPT_ENCODING"] gzip, deflate
_SERVER["HTTP_CACHE_CONTROL"] max-age=0
_SERVER["PHP_SELF"] /images/anotherphpscript.php
_SERVER["REQUEST_TIME_FLOAT"] 1398935271.6949
_SERVER["REQUEST_TIME"] 1398935271
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=68053&edit=1