Securing PHP installations

I have been using PHP for quite some time, and have developed a love-hate relationship with it. The ability to rapidly create dynamic web applications is extremely powerful, but PHP’s absymal security track record often leads me to wonder if I should be using it (especially since a fair number of opensource PHP applications are poorly coded, and using them can put your hosting platform at risk).

Over the past few months, I have spent a fair amount of time researching ways to protect my PHP enabled web servers from insecure code, and unknown PHP vulnerabilities. There are a number of ways you can tackle PHP security, the most important being designing and writing secure PHP code. The second way to protect your PHP applications is by applying the suhosin (formerly known as the hardended PHP patch) patch, which integrates a number of advanced security protections directly into the PHP runtime environment. The third method is to use an operating system that protects against stack and heap overflows, and the the last method is to tighten up the runtime environment by enabling one or more variables in the php.ini file.

Installing suhosin is extremely easy, and the benefits it provides are described on the suhosin website. To integrate suhosin into the PHP source code, you will first need to download and extract the PHP source code (you should also verify the public key signatures / MD5 checksums distributed with the source code):

$ wget http://us3.php.net/get/php-5.1.6.tar.gz/from/www.php.net/mirror

$ gtar xfvz php-5.1.6.tar

Once the PHP source code has been extracted, you will need to retrieve and apply the suhosin patch to the PHP source code (you can also compile suhosin as an extension, but I prefer to use the patch):

$ wget http://www.hardened-php.net/suhosin/_media/suhosin-patch-5.1.6-0.9.5.patch.gz

$ gunzip suhosin-patch-5.1.6-0.9.5.patch.gz

$ gpatch -p0 < suhosin-patch-5.1.6-0.9.5.patch
patching file php-5.1.6/configure
patching file php-5.1.6/configure.in
patching file php-5.1.6/ext/standard/basic_functions.c
patching file php-5.1.6/ext/standard/dl.c
patching file php-5.1.6/ext/standard/file.c
patching file php-5.1.6/ext/standard/file.h
patching file php-5.1.6/ext/standard/info.c
patching file php-5.1.6/ext/standard/syslog.c
patching file php-5.1.6/main/fopen_wrappers.c
patching file php-5.1.6/main/main.c
patching file php-5.1.6/main/php_config.h.in
patching file php-5.1.6/main/php.h
patching file php-5.1.6/main/php_logos.c
patching file php-5.1.6/main/snprintf.c
patching file php-5.1.6/main/spprintf.c
patching file php-5.1.6/main/suhosin_globals.h
patching file php-5.1.6/main/suhosin_logo.h
patching file php-5.1.6/main/suhosin_patch.c
patching file php-5.1.6/main/suhosin_patch.h
patching file php-5.1.6/main/suhosin_patch.m4
patching file php-5.1.6/sapi/apache/mod_php5.c
patching file php-5.1.6/sapi/apache2filter/sapi_apache2.c
patching file php-5.1.6/sapi/apache2handler/sapi_apache2.c
patching file php-5.1.6/sapi/cgi/cgi_main.c
patching file php-5.1.6/sapi/cli/php_cli.c
patching file php-5.1.6/TSRM/TSRM.h
patching file php-5.1.6/TSRM/tsrm_virtual_cwd.c
patching file php-5.1.6/TSRM/tsrm_virtual_cwd.h
patching file php-5.1.6/win32/build/config.w32
patching file php-5.1.6/Zend/Makefile.am
patching file php-5.1.6/Zend/zend_alloc.c
patching file php-5.1.6/Zend/zend_alloc.h
patching file php-5.1.6/Zend/zend.c
patching file php-5.1.6/Zend/zend_canary.c
patching file php-5.1.6/Zend/zend_compile.c
patching file php-5.1.6/Zend/zend_compile.h
patching file php-5.1.6/Zend/zend_constants.c
patching file php-5.1.6/Zend/Zend.dsp
patching file php-5.1.6/Zend/zend_errors.h
patching file php-5.1.6/Zend/zend.h
patching file php-5.1.6/Zend/zend_hash.c
patching file php-5.1.6/Zend/zend_llist.c
patching file php-5.1.6/Zend/ZendTS.dsp

After the suhosin patch is applied, you can configure and build PHP according to the PHP installation guide. The following example shows how to compile PHP with the most basic options:

$ ./configure –prefix=/opt/apache/php-5.1.6 –with-apxs2=/opt/apache/bin/apxs

$ make

$ make install

$ ln -s /opt/apache/php-5.1.6 /opt/apache/php

To verify that your module is built with the suhosin patch, you can run the php utility with the the “-i” (print PHP information) option:

$ /opt/apache/php/bin/php -i |more
phpinfo()
PHP Version => 5.1.6

System => SunOS web 5.10 Generic_118855-19 i86pc
Build Date => Oct 10 2006 17:10:49

[ ..... ]

This server is protected with the Suhosin Patch 0.9.5
Copyright (c) 2006 Hardened-PHP Project

If the string “This server is protected with the Suhosin Patch” is not listed in the php output, something most likely went wrong, and you will need to check the steps you used to integrate suhosin into the PHP source code. If the string is present, you can turn your attention to enabling stack and heap protections in your operating system (each OS handles this differently, so check google if you want more information), and modifying the php.ini file with more secure defaults.

The php.ini file is used to configure the PHP runtime environment, and there are several variables that can be set in the initiatialization file to provide a more secure execution environment. On the servers I support, I typically set the following variables (the items prefixed with a “;” are comments):

; Disable global variable registration
register_globals = Off

; Don’t display PHP errors
display_errors = Off

; Log all PHP errors to the Apache error log
log_errors = On

; Tell suhosin to log all security errors to syslog
suhosin.log.syslog = 511
suhosin.log.syslog.facility = 11
suhosin.log.syslog.priority = 4

; Verify that the uid the PHP script runs as is the
; same as the file they are trying to access, and
; escape backticks and disable shell exec()s
safe_mode = On

; Disable any and all execution of programs by
; setting safe_mode_exec_dir to an empty directory
; (and one that cannot have programs uploaded to it).
safe_mode_exec_dir = /opt/web/empty

; List the set of variables a user cannot change with putenv()
safe_mode_protected_env_vars = LD_PRELOAD, LD_LIBRARY_PATH, LD_RUN_PATH, PATH

; Set the directory where PHP programs can be run from
open_basedir = /opt/web/php_content

; Tell the PHP engine not to append anything to the
; web server “Server” header (NOTE: set ServerTokens
; to Prod if you are using Apache)
expose_php = Off

; Escape single quotes, double quotes, backslashes and
; NUL characters with a backslash
magic_quotes_gpc = On

; Disable dynamic loading of PHP extensions (this should be
; covered by safe_mode, but it’s ok to be extra safe)
enable_dl = Off

; Disable HTTP uploads to the server
file_uploads = Off

; Disable remote file opening
allow_url_fopen = off

Several of these variables WILL break existing applications, so you should evaluate their use prior to enabling them in a production environment. The combination of secure coding practices, operating system stack and heap overflow protections, suhosin, and a secure php.ini file should be used on every server that hosts a PHP runtime environment. If you take additional steps to secure PHP on your servers, please leave me a comment. I am always looking for new and interesting ways to protect the services I support!

3 Comments

judas_iscariote  on November 7th, 2006

Your tutorial is fine except two points actually..

1. you should not reccommend safe mode to be on, ’cause it produces more harm than good
2. Do not reccommend magic_quotes, they are not an effective way to secure websites since are unicode ingorant.

SneakyWho_am_i  on December 6th, 2008

I agree 100% with Judas.

1) Safe mode is great, actually I might turn it on for one of my hosts. However it doesn’t make your php “secure”. Obviously you know that, but still it can create a false sense of security. If you look at safe mode in the php manual (and other places) you’ll see that it’s not going to be included in PHP6. Partly because of the false sense of security that it creates, and partly because… Well, it exists just to fix shared hosting security, and that’s not really a PHP problem, is it?

I’m not saying outright don’t use Safe Mode, but I am saying don’t depend on it.

2) Magic Quotes in all its forms represents pure evil. The end doesn’t justify the means. As Judas points out, php will incorrectly assume that your content is in iso-8859-1 or some rubbish (even though my filesystem and scritps are all utf-8 I run into encoding problems). That’s not THE reason that it’s bad, but it is A reason. There are hacks involving using cleverly selected characters to trick php into escaping things which shouldn’t be escaped (thus creating string terminators) and the only way to prevent it in a safe mode environment is to unescape everything escaped by safe mode and then escape it again.

Granted, you’re using it to protect badly written scripts that you’ve downloaded and not things you’ve written itself, but it’s still considered bad form now to advise people to use magic quotes.
It lulls them into a false sense of security AND it encourages ridiculously sloppy and dangerous coding. Like Safe Mode it’s going to be removed for PHP6.

To begin to understand how bad PHP is with multibyte characters and such, consider the character “©” (copyright) … Pass it back and forth between htmlentities() and html_entity_decode() and see what you get back, you may be surprised. Not all of the magic quotes problems are related to codepages, but we must understand that if it can be befouled by “invalid” characters (and trust me, it can) then it’s already got one problem too many.

3) (bonus) Do XHTML pages validate if they contain   ? If so, then pages which are not well formed can validate…. Which is pretty bad and misleading for the Strict doctypes as XML doesn’t have a named entity “nbsp”, the only named entities are gt, lt, quot and amp

Yeah….. Using these things is not bad in itself. Safe Mode and Magic Quotes were both pure genius… But I don’t think that you should recommend it to others. If they need to be told how to use these things, then it would be safer if they were told to not.

SneakyWho_am_i  on December 6th, 2008

Oh another thing is, I administer some CentOS and Ubuntu servers for testing and such….

Ubuntu has a newer version of PHP (the php website recommends using the latest stable version for security reasons) and it comes with the Suhosin patch out of the box… So Ubuntu wins in default PHP security (by that way of measuring things… Rebuttal is of course welcome! I love both distributions!)

If you’re compiling all your own stuff then it doesn’t matter what’s in the repositories of course, but it’s still interesting to note this.

Leave a Comment