# PHP as a CGI with suEXEC or CGIWRAP

## smash

PHP as an apache module is nice, easy and fast, although PHP scripts run under the apache user, which can be an important problem and security issue, especially in a shared hosting environment.

The idea is to use a suid wrapper to run the CGI scripts under the username of the owner of the script. suEXEC and CGIWRAP can be used for this purpose.

http://cgiwrap.unixtools.org/

http://httpd.apache.org/docs/suexec.html

By running PHP as a CGI, it is possible to also run PHP scripts under the username of the owner of the script. Patches and different implementation exists to achieve this under suEXEC and CGIWRAP:

http://www.klaban.torun.pl/patches/cgiwrap/

http://www.cluecentral.net/suexec.html

(many similar suEXEC patches exist)

The difference between CGIWRAP and suEXEC is the integration with apache. CGIWRAP can be used with any web server supporting CGI's. This makes things a little bit more complicated for script owners who needs to know how it works and what it does. The following implementation makes it a lot easier:

http://steven.haryan.to/mod_cgiwrap/mod_cgiwrap.html

For those who cares, I have been using CGIWRAP in production environments for more than a year and I have faced and solved many issues. I also helped with the php-cgiwrap patch above.

Now, what if I want to use such setup under gentoo. This will require modifications of the apache and php ebuilds and if I choose to use CGIWRAP, a new ebuild will be needed for it. Also slightly different default configuration files for apache.

I have not yet decided whether suEXEC or CGIWRAP should be used. I will give mod_cgiwrap and suEXEC + php-patch a try in a test environment and I will see which one seems the best. Any opinions on this case appreciated.

The apache ebuild already compiles apache with suEXEC enabled. If suEXEC is to be used, it would be as easy as adding a new USE var:

"phpcgi"

If present, the ebuild for apache would add the php patch to suEXEC and the one for PHP would compile PHP as a CGI (the default way).

Suggestions? Opinions? Ideas? Flames?

----------

## SkiingYAC

mod_php currently cannot switch users, because it runs as the web server user.  There *must* be some way to combine suexec with mod_php so that the proper user can be attained by mod_php while it executes scripts.  I realize that is seems impossible given current the linux permissions system, but there has to be a better solution.

Suexec works because it is suid root.  Making apache or all of mod_php such appears to be a bad decision.  Mod_php runs as part of the apache process so it wouldn't be possible for it to run as different user than apache.  What if mod_php was suid root, and ran as a seperate process, or seperate set of processes (like mod_perl maybe...?), but when actually doing anything, it immediately switches to the user in question or to nobody.  It would act as a "dispatcher" for the necessary php processes with the correct userids.

Essentially, it stays root just long enough to figure out which user it should become, similar to suexec.  It would determine this by apache telling it the user.  Apache, running as nobody, can parse its config, match virtualhosts, etc, etc. and it doesn't matter.  Either it will pass mod_php a valid user/group id to run as, or not.  mod_php would never run as root past a certain point, and take security checks similar/identical to what suexec has.  

This solution is no less secure than suexec, provided that the same mechanism is used to check the sanity of what apache tells it.  PHP wouldn't have to be re-loaded over & over, and everything would work.

Is this possible?

----------

## klieber

moving to networking and security.

--kurt

----------

## Nitro

With Apache 2.0 this is possible, if mod_php is rewritten to support the new API.  Apache 2.0 supports MPMs (Multi-Processing Module), one MPM is called perchild ( http://httpd.apache.org/docs-2.0/mod/perchild.html ).  As far as I understand, it would allow you to make each apache child run as a different user, and if mod_php is compiled in, I would imagine that it too would run as that user.

Apache 2.0 is still to sketchy for me to play with, mainly because I don't have enough time.  :Sad: 

----------

## janus

Or you use php as CGI... i've written a patch for that to get it working with Apache2: http://janus.errornet.de/files/patches/apache2/apache2.0.40-php-cgi-suexec.diff

This works for the last 3 version of apache2 at minimum, i've it running on apache2.0.43 currently.

----------

## Xepher

OK, I searched and searched online for a way to do something like this.

I run a server with about 300 users. Each has full use of php, and their websites are available both as server.net/~username/script.php and username.server.net/script.php as well as the occasional seperate domain name. I tried using php's safe-mode for a while, but it pretty much did nothing when it came to letting users read/include each other's files. Plus it caused all sorts of other problems, as most scripts don't like it.

Anyway, I managed a solution...

First, compile php as a cgi executable. I actually modified the CLI ebuild for this. (The one that's just dev-php/php) If someone's interested in it, I can post it. The key point was changing the cli stuff to cgi instead. The other thing was to disable force-cgi-redirect. I put the final executable at /usr/bin/php-cgi

You can check what version of the php binary you have with php -v (or in my case, php-cgi -v) If it's the CLI version, it won't work. 

Next, I used the binfmt_misc trick to make php files executable, without the need for that pesky shebang #! First, make sure you have "misc binary support" enabled in your kernel.

Add this to fstab, and mount it.

```

binfmt_misc /proc/sys/fs/binfmt_misc/   binfmt_misc     defaults        0 0

```

Next, add these lines to /etc/conf.d/local.start

```

echo ':PHP:E::php::/usr/bin/php-cgi:' > /proc/sys/fs/binfmt_misc/register

echo ':PHP3:E::php3::/usr/bin/php-cgi:' > /proc/sys/fs/binfmt_misc/register

echo ':PHP4:E::php4::/usr/bin/php-cgi:' > /proc/sys/fs/binfmt_misc/register

```

Restart the local service 

```
/etc/init.d/local restart 
```

Now, any file that ends in those extensions will be run though php automagically.

Only one catch here, you must chmod u+x script.php The upside though, is that you can chmod 700 script.php as well. Even apache doesn't need permission for it. This makes it almost impossible (assuming the rest of your system is secure) for someone to steal passwords from forum configs and the like.

Now, assuming you have the default gentoo apache install... 1.3.27... Then suexec should already be compiled and set up properly. Only thing left to do. Add this line to your apache configs somewhere

```
AddHandler cgi-script .php .php4 .php3
```

Two more things. If you have mod_php installed, unmerge it, or at least comment it out of the apache configs. The last thing is that any directories with php scripts need to have ExecCGI directive enabled. The relevant section in my /etc/apache/conf/commonapache.conf file looks like this.

```

<Directory /home/*/public_html>

    AllowOverride All

    Options MultiViews ExecCGI Indexes Includes FollowSymLinks

    Order allow,deny

    Allow from all

</Directory>

```

Fairly simple, eh? No funky patches, and the only "odd" requirement on behalf of the users is the chmod u+x. I've found this to be a good thing though, as it forces them to look at file permissions, and hopefully they won't leave as many things at 777 from now on.

Oh, another tidbit. Use this to quickly chmod all those php files. (Yes, the semicolon is needed.)

```
find /home -iname "*.php" -exec chmod 700 \{\} \;

```

Now, if/when you run into problems. Check a couple of things. If you get that inevitable "premature end of script headers" then go to /etc/php4/php.ini and unset the doc_root. (You've no idea how long it took me to figure that one out.) Also, take a look at the logfile and  error_logging stuff, it'll quickly help you track down problems. Likewise /var/log/apache/suexec_log is your friend.

----------

## kip

you guys never heard of suphp(.org)? works great for me  :Smile: 

----------

## Xepher

Hmm... That might've been much simpler had I heard of it back then. Looking at suphp.org though, it really doesn't look any different from the normal su_exec module, save that it calls the php interpreter only... You still have to get a cgi build of php though, but I think it's finally in portage now. The misc-binary support does pretty much the same thing as suphp, when combined with su_exec, and keeps you from having to keep yet another package up to date. Is there some functionality that makes it better than the solution I suggested? (Aside from possible ease of installation.)

----------

## alain-

 *Xepher wrote:*   

> but I think it's finally in portage now

 Not really, or i am too dumb to find it. The "setuid root binary" sounds suspicious to me.

Anyways, the solution by Xepher is the cleanest, it seems. Nice would be an installation howto. This seems to be veery rare for php-cgi-environment

----------

## fleed

I think the cleanest solution is to use suphp. No messing about with either your existing php files or misc-binary. You really shouldn't need to change your kernel to run php securely!

----------

## chutz

 *Xepher wrote:*   

> Next, I used the binfmt_misc trick to make php files executable, without the need for that pesky shebang #! ...

 

Dude, you totally rule. That hint is exactly what I was looking for (for a long time).

Recompiling the kernel is a non-issue. If I want to keep a secure php, I shouldn't really bother that much. For a reason unknown, I don't have a /proc/sys/fs/binfmt_misc directory, but who cares -- I can mount it anywhere (/var/run is a good place). Could be because I compiled it as a module (wanted to try it right away).

I don't like the idea of suphp, as it is yet another packages that may fail, and I have no idea how secure it is -- suexec has been around for a long time, no need to trust my server over to some unknown project.

If performance with CGI is an issue -- comment-out mod_cgi in your conf (it's preferred over mod_cgid with non-threaded mpms) and leave only mod_cgid. As mentioned here: http://php.net/manual/en/security.cgi-bin.php#49904 the performance of cgid + php-cgi is comparable to that of mod_php. I haven't benchmarked myself, but maybe later.

----------

