Single PHP entry point with Nginx

  1. Introduction
  2. The Only Entry Point
  3. Security
  4. Limitations

In this article I will show you how to slightly increase application security, by exploiting the fact that Yii implements the Front Controller Pattern.

Introduction

While surfing the web, I noticed that most of the tutorials about configuring Nginx+PHP, propose the following pattern of invoking PHP:

	location ~ \.php$ {
	...
	}

That very line is used even in the official recommended configuration of Yii2.

The above directive instructs Nginx to pass every request, whose URL end with ".php" to the PHP interpreter. It works very well and is a nearly universal solution. But in fact, if you use Yii it is excessive.

The Only Entry Point

If you are somewhat familiar with Yii, you might already know that application lifecycle starts in the so called "entry script", usually named index.php. This is where the web application instance is created and request processing started.

The truth is that among all of the PHP files that an application consists of, only the entry script really should be invokable with PHP interpreter from the web! So the relevant part of Nginx config should resemble the following:

	location = /index.php {
		include fastcgi_params;
		fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
		fastcgi_pass   127.0.0.1:9000;
		#fastcgi_pass unix:/var/run/php5-fpm.sock;
		try_files $uri =404;
	}

	location ~ \.php$ {
		# prevent exposure of any other .php files!!!
		return 404;
	}

Security

One may ask how this rather subtle configuration change affects security. Here is a little example.

Imagine you have written and application, which among other things allows users to upload some files. Now, if you "forgot" to implement strict validation rules, malicious user could potentially upload (exploiting e.g. some NUL char vulnerability) file shell.php into the server's uploads folder.

Now the malicious user opens the URL: http://yourapp.net/uploads/shell.php

  • If the common configuration snippet was used, the request will be passed to the PHP - WIN for the hacker.
  • With the config from this article, the 404 Not Found will be shown - FAIL for the hacker :)

Limitations

The described approach is not always applicable. If you use some third party tools (e.g. KCFinder), which has its own scripts meant for web access (e.g. browser.php, upload.php etc), you will need to allow PHP for these scripts as well. Or better, write a Yii-compatible wrapper script, which will then pass request parameters from the entry script to a corresponding third party handler.