Bug #68053 [Opn->Wfx]: PHP-FPM with cgi.fix_pathinfo 0 loads script from PATH_TRANSLATED

From: 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

« previous php.bugs (#244126) next »