Wednesday, June 2, 2010

Stock CentOS with PHP SuPHP suhosin

SkyHi @ Wednesday, June 02, 2010

Stock CentOS with PHP SuPHP suhosin

From PhoenixWing
Jump to: navigation, search
This article pertains to installing PHP from source code, along with the suhosin hardening patch and extension, and the SuPHP PHP wrapper on a CentOS 5.x Linux system.

REMEMBER Always make backups!


Contents

[hide]




Necessary RPM's

The following non-PHP related RPM's were installed:
httpd httpd-devel mysql mysql-server mysql-devel
mod_ssl mod_auth_mysql perl-DBD-MySQL
In my case, I replaced the stock CentOS RPM's for MySQL with the one's from dev.mysql.com:
MySQL-client-community-5.1.22-0.rhel5.i386.rpm
MySQL-devel-community-5.1.22-0.rhel5.i386.rpm
MySQL-server-community-5.1.22-0.rhel5.i386.rpm
MySQL-shared-compat-5.1.22-0.rhel5.i386.rpm



Optional RPM's

I consider these to be mandatory on a modern web server for the mere fact, that nearly all web developers utilize third party web applications that make use of them. Graphics utilities like GD and ImageMagick are used by most forum & bulletin board applications, and even security software such as CAPTCHA's may use GD and/or ImageMagick. Other additions include mod_python & mod_perl for those web developers that want cutting edge scripting abilities. With "cutting edge" in mind, I also have a habit of including the following (and all their dependencies):
mod_perl mod_python libtidy libtidy-devel
gd gd-devel gd-progs ImageMagick ImageMagick-devel ImageMagick-perl



Download PHP, suhosin & SuPHP, then patch

  • I setup a directory on a large partition for my own compiles at /storage/compile/ and store my downloads in /storage/tarballs/, however, you can place the downloads wherever you see fit. At my place of employment, we store tarballs & source to be compiled in /usr/src/SCRIPTS/.
  • Untar/gunzip PHP, suhosing extensions & the patch file. Place the patch file outside of the PHP source directory:
mv suhosin-patch-5.2.5-0.9.6.2.patch /storage/compile/
  • Copy the suhosin extension source code into the PHP source tree's ext/suhosin directory:
cp -pr suhosin-0.9.22 /storage/compile/php-5.2.5/ext/suhosin
  • Patch PHP with the suhosing patch:
patch -p 1 -i ../suhosin-patch-5.2.5-0.9.6.2.patch
  • If successful, you should see something similar to:
patching file TSRM/TSRM.h
patching file TSRM/tsrm_virtual_cwd.c
patching file TSRM/tsrm_virtual_cwd.h
patching file Zend/Makefile.am
patching file Zend/Zend.dsp
...
patching file sapi/apache/mod_php5.c
patching file sapi/apache2filter/sapi_apache2.c
patching file sapi/apache2handler/sapi_apache2.c
patching file sapi/cgi/cgi_main.c
patching file sapi/cli/php_cli.c
patching file win32/build/config.w32



Configure & Compile PHP

  • Change to the PHP source directory:
cd /storage/compile/php-5.2.5/
  • Configure:
./buildconf --force

./configure --prefix=/usr --sysconfdir=/etc --with-config-file-path=/etc \
--enable-cgi --enable-force-cgi-redirect --enable-discard-path --with-mysql=/usr \
--enable-mbstring --with-bz2 --with-curl --enable-bcmath --enable-exif --with-gd \
--enable-gd-native-ttf --with-gettext --with-png-dir=/usr --with-jpeg-dir=/usr \
--with-freetype-dir=/usr --with-zlib --enable-calendar --with-openssl --with-gmp \
--enable-ftp --enable-magic-quotes --with-mcrypt --with-mhash --enable-ctype \
--enable-tidy --enable-dom --with-libxml-dir=/usr --enable-libxml --enable-xml \
--enable-xmlreader --enable-xmlwriter --enable-zip --enable-shmop --enable-wddx \
--with-pear --enable-pdo --with-pdo-mysql=/usr --disable-embedded-mysqli \
--with-mysqli=/usr/bin/mysql_config --enable-inline-optimization --enable-suhosin
  • Compile:
make
make test
make install
  • Copy the php.ini file to /etc:
cp ./php.ini-recommended /etc/php.ini
  • Edit /etc/php.ini to suit. I recommend the following changes:
Change:
short_open_tag = Off
To:
short_open_tag = On

Change (lets you see full error messages):
log_errors_max_len = 1024
To:
log_errors_max_len = 0

Change (security):
magic_quotes_gpc = Off
To:
magic_quotes_gpc = On

Change:
upload_max_filesize = 2M
To:
upload_max_filesize = 16M

Change (I've seen this needed on many app'z, like [http://gallery.sf.net Gallery]):
allow_url_include = Off
To:
allow_url_include = On

Change (Set to your timezone, as found in /usr/share/zoneinfo/):
;date.timezone =
To:
date.timezone = America/Phoenix



Install SuPHP

  • Untar/gunzip SuPHP source code, and go into the directory
cd /storage/compile/suphp-0.6.2
  • HACK: Edit the following with your favorite editor:
nano src/apache2/mod_suphp.c
- Find line 324 & 325
Change Line 324:
... suPHP_AddHandler", suphp_handle_cmd_add_handler, NULL, ACCESS_CONF, ...
To:
... suPHP_AddHandler", suphp_handle_cmd_add_handler, NULL, RSRC_CONF | ACCESS_CONF, ...
Change Line 325:
... suPHP_RemoveHandler", suphp_handle_cmd_remove_handler, NULL, ACCESS_CONF, ...
To:
... suPHP_RemoveHandler", suphp_handle_cmd_remove_handler, NULL, RSRC_CONF | ACCESS_CONF, ...
  • Configure suphp:
./configure --prefix=/usr --sysconfdir=/etc --enable-checkpath \
--with-apr=/usr --with-apxs=/usr/sbin/apxs --with-setid-mode=paranoid --with-min-uid=100 \
--with-min-gid=500 --with-apache-user=apache --with-logfile=/var/log/httpd/suphp_log

make
make install
  • Copy configuration file to /etc:
cp doc/suphp.conf-example /etc/suphp.conf
  • Create mod_suphp.conf file for apache:
cd /etc/httpd/conf.d/
nano -w mod_suphp.conf (or your editor of choice: vi, joe, elvis, etc)
  • mod_suphp.conf contents:
# This is the Apache server configuration file providing suPHP support.
# It contains the configuration directives to instruct the server how to
# serve php pages while switching to the user context before rendering.
LoadModule suphp_module modules/mod_suphp.so

# This option tells mod_suphp if a PHP-script requested on this server (or
# VirtualHost) should be run with the PHP-interpreter or returned to the
# browser "as it is".
suPHP_Engine on

# To use suPHP to parse PHP-Files
AddHandler x-httpd-php .php .php5 .php4 .php3 .phtml

# This option tells mod_suphp which path to pass on to the PHP-interpreter
# (by setting the PHPRC environment variable).
# Do *NOT* refer to a file but to the directory the file resides in.
#
# E.g.: If you want to use "/path/to/server/config/php.ini", use "suPHP_Config
# /path/to/server/config".
#
# If you don't use this option, PHP will use its compiled in default path.
suPHP_ConfigPath /etc

# If you compiled suphp with setid-mode "force" or "paranoid", you can
# specify the user- and groupname to run PHP-scripts with.
# Example: suPHP_UserGroup foouser bargroup
#
# -NOTE- WE SET THIS ON A PER VHOST SETTING. DON'T SET HERE
#
# suPHP_UserGroup apache apache

# This option tells mod_suphp to handle requests with the type .
# Please note this only works, if an action for the handler is specified
# in the suPHP configuration file.
suPHP_AddHandler x-httpd-php

# This option tells mod_suphp to NOT handle requests with the type .
# suPHP_RemoveHandler 
  • Edit /etc/suphp.conf:
Change:
logfile=/var/log/suphp.log
To:
logfile=/var/log/httpd/suphp_log

Change:
webserver_user=wwwrun
To:
webserver_user=apache

Change:
docroot=/
To:
docroot=/var/www/virtual/

Change (if you're not concerned with security):
errors_to_browser=false
To:
errors_to_browser=true

Change:
umask=0077
To:
umask=0133

Change:
min_gid=100
To:
min_gid=500

Change:
x-httpd-php=php:/usr/bin/php
To:
x-httpd-php=php:/usr/bin/php-cgi



Editing Apache and suPHP Configs

  • First, I want to stop the loading of mod_php, or the PHP Apache module, if it exists, so it does not load on startup. To do this, rename the php module config file:
mv /etc/httpd/conf.d/php.conf /etc/httpd/conf.d/php.conf.orig2007
  • Next, edit /etc/httpd/conf/httpd.conf file. In this example, we'll comment out a few global defaults, and make a few minor changes:
Change (For security reasons):
ServerTokens OS
To:
ServerTokens Prod

Change to your liking:

StartServers       8
MinSpareServers    5
MaxSpareServers   20
ServerLimit      256
MaxClients       256
MaxRequestsPerChild  4000

Example:

StartServers      10
MinSpareServers   10
MaxSpareServers   25
ServerLimit     1024
MaxClients      1024
MaxRequestsPerChild  4000



Change (if uncommented):
ServerName www.example.com:80
To:
#ServerName www.example.com:80


Change:
DirectoryIndex index.html index.html.var
To:
DirectoryIndex index.php index.html index.htm index.html.var


Change:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
To: (comment it out)
#LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined


Change:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
To: (comment out example, copy and change end from "combinedio" to "combined")
#LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combined


Change:
ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
To: (comment out global scope)
#ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"


Change:

AllowOverride None
Options None
Order allow,deny
Allow from all

To: (comment out)
#
#    AllowOverride None
#    Options None
#    Order allow,deny
#    Allow from all
#
Now add NameVirtualHost & VirtualHost directives. Note that I have included "suPHP_UserGroup userid groupid", required for suPHP to work properly AND I've also enabled SuEXEC for CGI scripts. Example:
NameVirtualHost ip.add.re.ss:80


ServerAdmin webmaster@int.domain
ServerName web.int.domain
ServerAlias *.web.int.domain

SuexecUserGroup userid groupid
suPHP_UserGroup userid groupid
ErrorLog logs/web.int.domain-error_log
CustomLog logs/web.int.domain-access_log combined

DocumentRoot /var/www/virtual/default_vhost/htdocs

Options -Indexes SymLinksifOwnerMatch
AllowOverride Options FileInfo AuthConfig Limit


ScriptAlias /cgi-bin/ "/var/www/virtual/default_vhost/cgi-bin/"

AllowOverride None
Options SymLinksifOwnerMatch
Order allow,deny
Allow from all


# Personal addition to disable TRACE method in Apache

RewriteEngine On
RewriteCond %{REQUEST_METHOD} ^TRACE
RewriteRule .* - [F]





Editing /etc/php.ini

Change the following under [sessions]:
session.save_path=/tmp/sess
Create the directory if necessary, and type:
chmod 1777 /tmp/sess



Creating a new /tmp if partition

If a /tmp partition was not created on a Linux system, you can go about creating one with the following:
cd /dev

# Create 500MB file for our /tmp partition. If you need
# more or less space, make count size larger or smaller.
dd if=/dev/zero of=tmpMnt bs=1024 count=500000

# Make an EXT3 filesystem for our tmpMnt file
/sbin/mke2fs -j /dev/tmpMnt

# Backup your /tmp dir- I had mysql.sock file that I
# needed to recreate the symbolic link for. Other
# programs may use it to store cache files or whatever.

cd /
cp -r /tmp /tmp_backup

# Mount the new /tmp filesystem with noexec, nosuid
# and read/write, and set permissions.
mount -o loop,noexec,nosuid,rw /dev/tmpMnt /tmp
chmod 1777 /tmp

# Copy everything back to new /tmp and remove backup
cp -r /tmp_backup/* /tmp/
rm -rf /tmp_backup


REFERENCES
http://www.phoenixwing.com/wiki/Stock_CentOS_with_PHP_SuPHP_suhosin#Download_PHP.2C_suhosin_.26_SuPHP.2C_then_patch