I set up a server which just went into production mode and we have realized that there's a problem with our mod_rewrite redirects if they try to re-route a PHP file that doesn't exist. The server's running apache 2.4.18 and PHP-FPM 7.0. It's the FPM part that I'm unaccustomed to. The apache guys on the Freenode IRC channel insisted that I should use the event MPM. One instructs apache to handle PHP files with this ProxyMatch directive within my VirtualHost directive:

        <VirtualHost _default_:443>
                ServerAdmin webmaster@localhost
                DocumentRoot /var/www/html

            # THIS IS IT RIGHT HERE
            ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:/run/php/php7.0-fpm.sock|fcgi://localhost/var/www/html/
    </VirtualHost>

The problem with this is that a request for some nonexistent file like http://example.com/path/to/file/that/does/not/exist.php will cause a 404 FILE NOT FOUND error before my mod_rewrite rules in an .htaccess file have a chance to redirect this request.

I found some helpful detail in the apache wiki but there's a warning about security at the bottom:

/uploads/malicious.jpg/lalalaalala.php

Would lead php-fpm to process that file (/uploads/malicious.jpg), and without certain sanity check, possibly lead to a compromised server.

Has anyone dealt with this issue in a way that is secure?

    Hmm, plowing in deep dirt there ... I may not be the guy. As far as security ... are you allowing uploads? If not, I wouldn't be too concerned about that attack vector, although there may be others.

    As far as the ProxyPass being superseded by the 404, what if that config directive went into a config file instead of .htaccess? Or does the app have to be more portable than that?

    dalecosp

    First things first. This mostly works:

    # WORKS! mostly...except if the php file doesn't exist then it's 404 and I get no redirects
    ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:/run/php/php7.0-fpm.sock|fcgi://localhost/var/www/html/

    The problem is that any url request that contains the string ".php" gets a 404 if it doesn't correspond to an actual PHP file. E.g., if I request http://example.com/this/file/does/not/exist.php then I always get a 404 and my mod_rewrite rules never get evaluated.

    I read up on the issue and tried this, but it totally fails -- I get 404 for all of my PHP files:

    <Proxy "unix:/run/php/php7.0-fpm.sock|fcgi://localhost/var/www/html/" enablereuse=on max=10>
    </Proxy>
    <FilesMatch "\.php$">
           <If "-f %{REQUEST_FILENAME}">
                   # If your version of httpd is 2.4.9 or newer (or has the back-ported feature), you can use the unix domain socket
                   SetHandler "proxy:unix:/run/php/php7.0-fpm.sock|fcgi://localhost/var/www/html/"
           </If>
    </FilesMatch>

    I feel like I'm close, but my command of these apache directives and proxies and socks and stuff are inadequate. This is fairly urgent.

      Right, but where is this ProxyPass line kept ... in .htaccess or in a config file? Because config files (e.g. httpd.conf, VirtualHost includes, etc.) supersede .htaccess and can sometimes solve chicken/egg issues.

        4 months later

        I know it's been ages since I posted this, but I figure I should report back.

        This ProxyPassMatch directive is in the apache configuration file in /etc/apache2/sites-available/. Clearly, by the apache rules the ProxyPassMatch directive gets executed before any .htaccess file rules get interpreted. That being the case, the request matches that directive for any request ending in .php:

        ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:/run/php/php7.0-fpm.sock|fcgi://localhost/var/www/html/

        Because of this, any request for a string ending in .php gets passed to the PHP-FPM pool which tries to execute the PHP file.

        I solved the 404 not found problem for my particular situation by adding additional (and quite ad-hoc) redirect rules in the apache conf file BEFORE this ProxyPassMatch directive. This has the effect of rewriting things before PHP-FPM gets run on any file.

        Sadly, the risk described in the apache wiki is still a problem. That wiki recommends
        - keeping uploaded files outside the document root
        - scrutinizing pathinfo
        - php-fpm should check if the script being invoked is allowed
        - If such restrictions cannot be implemented easily, then checks could be performed prior to proxying with a RewriteCond or FallbackResource to ensure that the URI is not altered by the HTTP client

        It sounds to me like apache is punting to PHP on this security matter.

          Write a Reply...