Hero Image

Safer PHP

Safer PHP

Setting up PHP is always a bit tricky, and you should consider some pitfalls. The example below should help get you on your way.

Website with many accessed PHP-files.

Most websites will host multiple applications (and not just a CMS). Therefore you will need something like the following:

server {
    ...
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?xxx...; 
    }

    ...

    location ~ \.php$ {
        # This splits the URI into two variables:
        fastcgi_split_path_info ^(.+\.php)(/.+)$;

        # First, make a copy of $fastcgi_path_info, due to try_files
        # making $fastcgi_path_info empty after doing the try_files.
        set $path_info $fastcgi_path_info;

        # For the sake of security, don't pass non-existing files.
        try_files $fastcgi_script_name =404;

        # 1) $fastcgi_script_name for SCRIPT_FILENAME
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

        # 2) The copied $fastcgi_path_info for PATH_INFO
        fastcgi_param PATH_INFO $path_info;

        # Include other environment defaults for FastCGI.
        include fastcgi_params;

        # This is the socket of the running PHP-FPM.
        fastcgi_pass finalx:9000;
    }
}

Websites with just one accessed PHP-file.

If you know that your entire website will be run through a single PHP-file (and its includes), like for example a CMS like Pagekit, you could use this instead. Safer (can't access other scripts) and performing slightly better (no more need for try_files).

Below an example:

server {
    ...

    index index.php;

    location / {
        try_files $uri $uri/ /index.php?xxx...; 
    }

    ...

    # The = in the location is an "exact"-identifier.
    # Without it, it would be matching the 404 section below.
    location = /index.php {
        # This splits the URI into two variables:
        fastcgi_split_path_info ^(.+\.php)(/.+)$;

        # 1) $fastcgi_script_name for SCRIPT_FILENAME
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

        # 2) $fastcgi_path_info for PATH_INFO
        fastcgi_param PATH_INFO $fastcgi_path_info;

        # Include other environment defaults for FastCGI.
        include fastcgi_params;

        # This is the socket of the running PHP-FPM.
        fastcgi_pass finalx:9000;
    }

    # WARNING: Do not forget this or your PHP-scripts can be accessed
    # directly and possibly expose code you don't want others to see.
    # All other PHP-files should just return a "404 Not Found".
    location ~ \.php$ {
        # Use 404 and not 403, that way attackers will not be wiser as
        # to the existence of a file and think it does not exist.
        return 404;
    }
}