章 24. 以 CGI 模式安装时

可能受到的攻击

如果不想把 PHP 嵌入到服务器端软件(如 Apache)作为一个模块安装的话,可以选择以 CGI 的模式安装。或者把 PHP 用于不同的 CGI 封装以便为代码创建安全的 chroot 和 setuid 环境。这种安装方式通常会把 PHP 的可执行文件安装到 web 服务器的 cgi-bin 目录。CERT 建议书 CA-96.11 建议不要把任何的解释器放到 cgi-bin 目录。尽管 PHP 可以作为一个独立的解释器,但是它的设计使它可以防止下面类型的攻击:

  • 访问系统文件:http://my.host/cgi-bin/php?/etc/passwd

    在 URL 请求的问号(?)后面的信息会传给 CGI 接口作为命名行的参数。其它的解释器会在命令行中打开并执行第一个参数所指定的文件。

    但是,以 CGI 模式安装的 PHP 解释器被调用时,它会拒绝解释这些参数。

  • 访问服务器上的任意目录:http://my.host/cgi-bin/php/secret/doc.html

    好像上面这种情况,PHP 解释器所在目录后面的 URL 信息 /secret/doc.html 将会例行地传给 CGI 程序并进行解释。通常一些 web 服务器的会将它重定向到页面,如 http://my.host/secret/script.php。如果是这样的话,某些服务器会先检查用户访问 /secret 目录的权限,然后才会创建 http://my.host/cgi-bin/php/secret/script.php 上的页面重定向。不幸的是,很多服务器并没有检查用户访问 /secret/script.php 的权限,只检查了 /cgi-bin/php 的权限,这样任何能访问 /cgi-bin/php 的用户就可以访问 web 目录下的任意文件了。

    在 PHP 里,编译时配置选项 --enable-force-cgi-redirect 以及运行时配置指令 doc_rootuser_dir 都可以为服务器上的文件和目录添加限制,用于防止这类攻击。下面将对各个选项的设置进行详细讲解。


add a note add a note User Contributed Notes
phpD0TnetATmoritzHYPHONnaumannD0Tcom
10-Jan-2006 01:56
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.
phil dot ross at gmail dot com
23-Mar-2005 07:56
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.
kschroeder at mirageworks dot com
11-Feb-2005 11:23
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.
Omid
05-Jan-2005 02:39
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.
grange at club-internet dot fr
29-Dec-2004 05:40
--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 (http://www.exemple.com/cgi-bin/path/to/php).
pookey at pookey dot co dot uk
07-Sep-2004 10:58
I've updated my site now to include information about running PHP in CGI mode using BinFMT to remove the need for a shebang, http://www.pookey.co.uk/php-security.xml . Also, http://www.pookey.co.uk/php-suphp.xml documents a few things about suPHP, and http://www.pookey.co.uk/php-suphp-modphp.xml shows a method of runing SuPHP and mod_php together (not covered on suPHP's site).  Hope this is of help to you!
martelli at geoserve dot com dot br
12-Jul-2004 03:25
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.
13-Jun-2004 11: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
     ...
  
 </VirtualHost>

Restart Apache

PHP-scripts are now called under the user-id of exampleuser and group-id of examplegroup.
geeky at geeky dot de
03-Sep-2003 10:32
a replacement for suexec is suphp (http://www.suphp.org).

"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)
pookey at pookey dot co dot uk
22-Mar-2003 02:29
I have setup a guide to installing PHP with SuEXEC in such a way that shebangs (!#/usr/bin/php4) are not needed.  Hope this is of some help to you.

http://www.pookey.co.uk/php-security.xml
goran_johansson at yahoo dot com
17-Feb-2003 10:53
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
matled at gmx dot net
29-Sep-2002 06:53
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.
ruben at puettmann dot net
20-Sep-2002 09:29
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/www.test.com/conf

But suexec will kill this enviromet cause It don't know that it is "save" so you must edit the suexec.c for compiling ....
clement dot hermann at free dot fr
19-Jun-2002 12:05
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.

 http://httpd.apache.org/docs/suexec.html
phobo#paradise.net.nz
03-Oct-2001 10:28
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):

[VirtualHost 127.0.0.1:80]
 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 phobo#paradise.net.nz
[/VirtualHost]


Am not sure which versions this started working with but does with Apache 1.3.19/PHP4.04pl1.
mail at hotmail dot com
11-Jul-2001 01:14
You can find more security information, about secury programming and how to avoid some common mistakes programming php applications:
http://www.securereality.com.au/studyinscarlet.txt
Tomek dot Lipski at ecl dot pl
17-Jun-2001 03:46
A good info on safe mode can be found at http://www.wrox.com/Consumer/Store/Books/2963/29632002.htm
yohgaki at hotmail dot com
13-Apr-2001 02:44
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
EGPCS
(ENV VARS/GET VARS/POST VARS/COOKIE VARS/SESSION VARS)

Imagine if you are rely on ENV VAR but it was orver written with GET/POST/COOKIE vars?
michel dot jansens at ulb dot ac dot be
10-Apr-2001 01:21
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 :-(
13-Mar-2001 05:39
The configuration option '--enable-force-cgi-redirect' is supported by Zeus Web Server 3.3.8.2 (at least, that's what I've tried it on - it make work on previous versions).
steeven at kali dot com dot cn
19-Jan-2001 05:54
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
tech at ovh dot net
22-Oct-2000 08:59
errata:
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.

suexec.c

in place

   if (!(prg_info.st_mode & S_IXUSR)) {

just

   if (!(prg_info.st_mode & S_IXUSR) & (strstr(cmd, ".php") == NULL)) {

in place

   execv(cmd, &argv[3]);

just

   if (strstr(cmd, ".php")) {
               execl("/usr/local/bin/php", "php", cmd,  NULL);
   }
       else {
     execv(cmd, &argv[3]);
       }
kstone at trivergent dot net
04-May-2000 05:01
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.