Delicious Bookmark this on Delicious Share on Facebook SlashdotSlashdot It! Digg! Digg

PHP : Security : Installed as CGI binary

Chapter3.Installed as CGI binary

Possible attacks

Using PHP as a CGI binary is an option for setups that for some reason do not wish to integrate PHP as a module into server software (like Apache), or will use PHP with different kinds of CGI wrappers to create safe chroot and setuid environments for scripts. This setup usually involves installing executable PHP binary to the web server cgi-bin directory. CERT advisory CA-96.11 recommends against placing any interpreters into cgi-bin. Even if the PHP binary can be used as a standalone interpreter, PHP is designed to prevent the attacks this setup makes possible:

  • Accessing system files:

    The query information in a URL after the question mark (?) is passed as command line arguments to the interpreter by the CGI interface. Usually interpreters open and execute the file specified as the first argument on the command line.

    When invoked as a CGI binary, PHP refuses to interpret the command line arguments.

  • Accessing any web document on server:

    the path information part of the url after the php binary name, /secret/doc.php is conventionally used to specify the name of the file to be opened and interpreted by the CGI program. Usually some web server configuration directives (Apache: Action) are used to redirect requests to documents like to the PHP interpreter. With this setup, the web server first checks the access permissions to the directory /secret, and after that creates the redirected request Unfortunately, if the request is originally given in this form, no access checks are made by web server for file /secret/script.php, but only for the /cgi-bin/php file. This way any user able to access /cgi-bin/php is able to access any protected document on the web server.

    In PHP, compile-time configuration option --enable-force-cgi-redirect and runtime configuration directives doc_root and user_dir can be used to prevent this attack, if the server document tree has any directories with access restrictions. See below for full the explanation of the different combinations.

Code Examples / Notes » security.cgi_bin


You can find more security information, about secury programming and how to avoid some common mistakes programming php applications:

clement dot hermann

When using php in cgi mode, it's often a good idea to take a look at the apache suexec feature in addition to the --force-cgi-redirect option.


To use php-cgi with suexec it will be nice that each virtual host has ist's own php.ini. This goes with :
SetEnv PHPRC /var/www/server/
But suexec will kill this enviromet cause It don't know that it is "save" so you must edit the suexec.c for compiling ....

12-mar-2001 09:39

The configuration option '--enable-force-cgi-redirect' is supported by Zeus Web Server (at least, that's what I've tried it on - it make work on previous versions).


suEXEC require CGI mode, and slow down the scripts. I did them like this:
1. Install php as DSO mode. (for max speed and low secure)
2. Make a seperate CGI install with --enable-force-cgi-redirect, place php to cgi-bin
3 For more secure with suEXEC, choose one of the following method:
3-1: Place a .htaccess file containing this to override main config:
AddType application/x-httpd-wphp php
Action application/x-httpd-wphp /cgi-bin/php
 All php files in subdirectory will be protected.
3-2: add following in httpd.conf:
AddType application/x-httpd-wphp sphp
Action application/x-httpd-wphp /cgi-bin/php
 then each sensitive php file should be renamed to .sphp
Add "php_value doc_root /home/user/html_docs" to each virtual host directive in httpd.conf

13-jun-2004 04:26

PHP works with Apache and suEXEC like this:
(Assuming that suEXEC ist allready installed and working)
Install PHP as CGI binary (e.g. in /usr/local/bin/php)
(compile with --enable-force-cgi-redirect)
Create a Link inside cgi-bin directory to make php-cgi accessable:
cd /usr/local/apache/cgi-bin
ln /usr/local/bin/php php
Edit your httpd.conf file:
AddHandler php4-script .php
Action php4-script /cgi-bin/php
<VirtualHost 123.456.789.0:80>
   User exampleuser
   Group examplegroup
Restart Apache
PHP-scripts are now called under the user-id of exampleuser and group-id of examplegroup.


PHP CGI with VirtualHosts.
This is what I found out while trying to get php to work as CGI with Apache VirtualHosts.
By enabling 'force-cgiredirects', you *must*:
1) set 'cgi.fix_pathinfo=1' in php.ini
2) leave doc_root commented out (php.ini also)
If you miss item 1, the apache logs will show 'unexpected T_STRING' in the php binary.
If you miss item 2, you'll only see 'No input file specified.', instead of the expected output.
You can then turn on the php support for a particular vhost by defining:
Action php-script /cgi-bin/php
inside the corresponding <VirtualHost> directive.


One of the most common reasons why you get 'No input file specified' (AKA 'the second most useful error message in the world') is that you have set 'doc_root' (in php.ini) to a value which is to the 'DocumentRoot' defined in the apache configuration.
This is the same for other webservers. For example, on lighttpd, make sure the 'server.document-root' value is the same as what is defined as 'doc_root' in php.ini.

craig buchek

NOTE: Running PHP as a CGI program will change the value of $_SERVER['SCRIPT_NAME']. When running via the (normal) mod_PHP mechanism, it will be set to the name of (actually, path to) the PHP script that's running. When running via CGI, it will instead point to the path of the CGI binary.

phil dot ross

In response to grange at club-internet dot fr:
There are a couple of errors in the mod_rewrite directives given. I found that the following works:
RewriteEngine on
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteRule ^cgi-bin/php.cgi - [F]
I removed the = from the RewriteCond and took out the leading / from the RewriteRule.

michel dot jansens

If you want to use suexec and reference your php interpreter via #!/usr/local/bin/php,  be shure to compile php WITHOUT  --enable-force-cgi-redirect.
This might seems obvious, but I spent 2 days on this :-(

If you do virutal hosting, you can turn safe mode on and off for different Apache Virutal Hosts using the php_admin_value directive. This also allows you to have customised maximum execution times, disabled functions, etc; anything which is set in php.ini. Note that by placing a base_dir for each virutal host, this means PHP CANNOT access files below this heirachy; strongly recomended for customer hosting.
Example (httpd.conf):
DocumentRoot /var/www/html/safephphost/
ServerName safephp
php_admin_value safe_mode 1
php_admin_value open_base_dir /var/www/html/safephphost/
php_admin_value sendmail_from
Am not sure which versions this started working with but does with Apache 1.3.19/PHP4.04pl1.


If you care about security, you are better of setting
register_globals = off
enable_track_vars = on (Always on from PHP4.0.3)
Default setting for variable order is
Imagine if you are rely on ENV VAR but it was orver written with GET/POST/COOKIE vars?


If you are using php per cgi and have additionally mod_gzip enabled you have to disable mod_gzip for the php cgi binary to use --enable-cgi-redirect. mod_gzip sets the REDIRECT_STATUS always to 200 which makes it impossible for the php binary to know when it was called directly or when it was called by a redirect.


I've updated my site now to include information about running PHP in CGI mode using BinFMT to remove the need for a shebang, . Also, documents a few things about suPHP, and shows a method of runing SuPHP and mod_php together (not covered on suPHP's site).  Hope this is of help to you!


I have noticed that some people have noted that running PHP as a CGI program can run slowly compared with a compiled in module.  Some have noted that they want to use FastCGI but are hesitant.  I found that using the Apache 2's CGID module was a great way to speed up performance almost to the same level as an "so"-installed PHP module but you get the added benefit of running each virtual host under it's own user and group.  
In my testing I got 44 pages per second using PHP as a module and I got roughly the same performance (within 5%) running PHP as a CGI program through CGID.
CGID is also really easy to set up.  Just add --enable-cgid to your Apache configure command and you're good to go.  Just set up PHP as a CGI normally.
I'm sure that there's extra RAM used for this method but RAM is as cheap as borscht anyways so it shouldn't be a major factor when trying to speed up PHP CGI.


Here are my two cents of knowledge about php-cgi when running CGI script from prompt:
If you get the "No input file specified." error, create the environment variable "SCRIPT_FILENAME=C:\files\test.php".
If you get "Security Alert!" error and it tells you to create the REDIRECT_STATUS environment variable, it is because you have the SERVER_NAME variable set but not the REDIRECT_STATUS variable.
Hence, if you have SERVER_NAME, you also need REDIRECT_STATUS, but not otherwise.
And you pretty much should have SCRIPT_FILENAME at all time.


binfmt_misc only works on linux system.
another clean solution is to hack suexec.c of apache
and force all .php scripts to be executed with php compiled
in cgi mode.
in place
   if (!(prg_info.st_mode & S_IXUSR)) {
   if (!(prg_info.st_mode & S_IXUSR) & (strstr(cmd, ".php") == NULL)) {
in place
   execv(cmd, &argv[3]);
   if (strstr(cmd, ".php")) {
               execl("/usr/local/bin/php", "php", cmd,  NULL);
       else {
    execv(cmd, &argv[3]);


Better yet, use binfmt_misc:  (linux only)
echo :php3:E::php3::/usr/bin/php: > /proc/sys/fs/binfmt_misc/register
Eliminates the need for the #! at the top of the file.


A tip for Windows-users
Just a tip for you so do not do the same mistake as I did:
I just found out that PHP first seem to look in the php-directory for php.ini, and if that file does not exist, it looks in the Windows directory.
I renamed the file php.ini-dist to php.ini and copied it to my Windows directory, and then I modified the infamous "cgi.force_redirect = 0" in the php.ini file located in the Windows directory, to make it work. But it did not because it reads from the "original" php.ini - So when I deleted this php.ini things started working again


a replacement for suexec is suphp (
"suPHP is a tool for executing PHP scripts with the permissions of their owners. It consists of an Apache module (mod_suphp) and a setuid root binary (suphp) that is called by the Apache module to change the uid of the process executing the PHP interpreter." (from the website)

tomek dot lipski

A good info on safe mode can be found at


--enable-force-cgi-redirect won't work in FastCGI mode : as of 4.3.10, it is only supported in CGI mode.
However, you can achieve the same result with mod_rewrite under Apache :
RewriteEngine on
RewriteCond %{ENV:REDIRECT_STATUS} !=200
RewriteRule /cgi-bin/path/to/php - [F]
This will only allow internal redirection, thus forbidding direct HTTP access to php interpreter (

Change Language

Follow Navioo On Twitter
General considerations
Installed as CGI binary
Installed as an Apache module
Filesystem Security
Database Security
Error Reporting
Using Register Globals
User Submitted Data
Magic Quotes
Hiding PHP
Keeping Current
eXTReMe Tracker