# rm-rf.es | Administración de sistemas

Bitácora personal de un SysAdmin Gnu/Linux, Windows, BSD...

Instalación y configuración de suPHP


suPHPHe hablado varias veces sobre configuraciones y posibles errores de suPHP pero nunca sobre el modo de instalarlo. Para quienes no lo sepan, suPHP es un módulo de Apache y a su vez una utilidad independiente que permite que los scripts PHP se ejecuten con el usuario propietario del script. Así mismo, permite establecer restricciones de seguridad como evitar permisos 777 en directorios, establecer un UID y GID mínimos para los usuarios, forzar a que los scripts de encuentren en el document_root del host, etc.

La instalación es sencilla. Vamos a suponer que tenemos tanto Apache como PHP compilados o instalados. La forma más sencilla de activar suPHP es instalando el rpm disponible desde el sitio web oficial, aunque por supuesto podemos compilarlo con los requerimientos que tengamos bajando las sources.

En el caso de rpm, para RHEL, CentOS, Scientific Linux, etc es tan sencillo como bajar el rpm de nuestra arquitectura e instalarlo:

# wget http://pkgs.repoforge.org/mod_suphp/mod_suphp-0.7.1-1.el6.rf.x86_64.rpm
# rpm -ivh mod_suphp-0.7.1-1.el6.rf.x86_64.rpm

Una vez instalado, se debería haber creado el fichero de configuración en /etc/httpd/conf.d/suphp.conf. Antes de nada, debemos mover, eliminar o comentar todo el contenido del fichero /etc/httpd/conf.d/php.conf para no cargar el módulo DSO de php, que como sabéis hace que todos los scripts php se ejecuten con el usuario de Apache (www-root, apache, nobody…) con el problema de seguridad que conlleva.

Lo más importante del fichero de configuración es tener cargado el módulo y especificados los handler que dirán como gestionar los scripts php, así como tener el motor de suPHP activado:

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
AddHandler x-httpd-php .php .php4 .php3 .phtml

El otro fichero de configuración crítico es /etc/suphp.conf, cuyas variables son suficientemente descriptivas, los valores por defecto son válidos para una configuración correcta. Tened en cuenta únicamente el bug que ya comenté de los handlers. Revisad la documentación oficial para más info.

[global]
logfile=/var/log/httpd/suphp_log
loglevel=info
webserver_user=apache
docroot=/
env_path=/bin:/usr/bin
umask=0077
min_uid=500
min_gid=500

; Security options
allow_file_group_writeable=false
allow_file_others_writeable=false
allow_directory_group_writeable=false
allow_directory_others_writeable=false

;Check wheter script is within DOCUMENT_ROOT
check_vhost_docroot=true

;Send minor error messages to browser
errors_to_browser=false

[handlers]
;Handler for php-scripts
x-httpd-php="php:/usr/bin/php-cgi"

;Handler for CGI-scripts
x-suphp-cgi="execute:!self"

Finalmente, en cada virtualhost tendremos que especificar el usuario y grupo que ejecutará los scripts php, usamos la directiva suPHP_UserGroup en cada Virtualhost:

suPHP_UserGroup usuario grupo

Validamos la configuración y reiniciamos Apache. Tened en cuenta las siguientes consideraciones básicas (revisad los logs de errores de Apache y suPHP porque tendréis seguro algunos), por defecto tenemos lo siguiente:

  • Los scripts php no pueden tener permiso de escritura para el grupo ni para el resto, es decir, lo máximo sería 0644
  • Los directorios no pueden tener permisos para otros ni el grupo, es decir, 777 no es válido y 775 tampoco, recomendable 755.
  • Las directivas php_flag de .htaccess pasan a un fichero php.ini en la misma ruta con el formato estándar de php.
  • El propietario y grupo de los scripts debe ser el especificado en suPHP_UserGroup.

suPHP 0.7.1: SecurityException in Application.cpp:511: Unknown Interpreter: php


Hoy he estado actualizando un equipo. Una de las actualizaciones era la de la versión de suPHP a la 0.7.1. La actualización ha ido bien hasta que he comenzado a probar los sitios web.

Todos recibían un error 500 (Internal Server Error), típico de suPHP, y en los logs se volcaba la siguiente información:

[Sun Oct 17 19:08:03 2010] [error] [client XX.XX.XXX.XX] SecurityException in Application.cpp:511: Unknown Interpreter: php
[Sun Oct 17 19:08:03 2010] [error] [client XX.XX.XXX.XX] Premature end of script headers: index.php

En este momento ya había entrado en modo pánico, pero rebuscando por Internet información sobre esta versión, he visto que había un pequeño cambio o bug (bueno, pequeño…) por el cual, en el fichero de configuración de suPHP (/etc/suphp.conf) los handlers tenían que ir entre comillas:

Antes:

;Handler for php-scripts
x-httpd-php=php:/usr/bin/php-cgi

;Handler for CGI-scripts
x-suphp-cgi=execute:!self

Después:

;Handler for php-scripts
x-httpd-php="php:/usr/bin/php-cgi"

;Handler for CGI-scripts
x-suphp-cgi="execute:!self"

Tras este cambio, y reiniciar apache todo ha vuelto a funcionar a la normalidad.

suPHP: “Premature end of script headers” en el error_log


Si acabáis de montar un servidor apache con suPHP y al tratar de ejecutar cualquier PHP el navegador muestra “Internal Server Error“, y el log de apache muestra “Premature end of script headers” lo más probable es que hayáis instalado la versión cliente (CLI) de php en vez de la versión CGI (php-cgi). Para solventar esto debéis copiar el binario de php CGI en donde se supone debe estar instalado el binario de php (donde vaya apache a buscarlo vamos).

En mi caso, en un servidor CentOS el binario php-cgi estaba aquí:

/usr/bin/php-cgi

Y apache utilizaba el binario de php-cliente:

/usr/bin/php

Bien, entonces he guardado un backup del cliente y he creado un enlace simbólico para que /usr/bin/php sea lo mismo que /usr/bin/php-cgi, podéis también sobreescribirlo, lo que queráis. Con este cambio el problema debería quedar solucionado.

suPHP: “/…/” is not in document root of Vhost “/…/”


[Mon Aug 18 04:00:06 2008] [error] [client xx.xx.xx.xx] SoftException in Application.cpp:217: File "/usr/share/phpmyadmin/index.php" is not in document root of Vhost "/var/www/html/"

Este error es provocado a una restricción de seguridad en servidores con Apache con suPHP. Si véis conveniente la resolución del mismo, debéis acceder al fichero de configuración de suphp, normalmente ubicado en /etc/suphp.conf, y hacer lo siguiente:

Modificar esta linea:

;Check wheter script is within DOCUMENT_ROOT
check_vhost_docroot=true

Por esto:

;Check wheter script is within DOCUMENT_ROOT
check_vhost_docroot=false

Y solucionado, ya depende de cada uno si ve correcto quitar la restricción de seguridad o solventar el problema de rutas. Como habréis comprobado, la directiva evita que se acceda a fichero o carpetas que se encuentran fuera del DocumentRoot establecido en el Virtualhost.

Utilizar .htaccess / php.ini en Apache con suPHP


En el momento que compilas apache con suPHP, las directivas incluidas dentro de los ficheros .htaccess dejan de funcionar. Existen dos posibilidades, compilar htscanner para permitir el uso de ficheros .htaccess y todas las directivas que hay dentro de él, o usar un fichero php.ini personalizado dentro de cada virtualhost con las directivas que queramos.

Si preferís la opción de seguir usando .htaccess, acceder aquí para seguir las instrucciones de htscanner, no obstante es mucho más sencilla la segunda opción.

Para la segunda opción, pongamos el caso que para un virtualhost concreto, queremos añadir personalizaciones en un fichero php.ini, para ello añadimos la siguiente línea a su virtualhost, con la ruta en la que se encuentra el fichero php.ini personalizado:

SuPHP_ConfigPath /home/dominio/

Hay que tener en cuenta, que en los php.ini, y suPHP en general no acepta directivas del tipo php_flag o php_admin_flag, os pongo unos ejemplos de como realizar el cambio para que php.ini lo acepte:

Si queremos pasar esta información de un .htaccess:

$ cat .htaccess
php_admin_flag short_open_tag On
php_admin_flag safe_mode Off
php_admin_flag register_globals Off
php_admin_flag magic_quotes_gpc On
php_admin_flag magic_quotes_runtime Off

En un php.ini sería así:

$ cat php.ini
short_open_tag= On
safe_mode= Off
register_globals= Off
magic_quotes_gpc= On
magic_quotes_runtime= Off

En este caso, ubicaríamos el php.ini en /home/dominio/php.ini, y el dominio configurado dentro de este virtualhost recogería estas directivas personalizadas.

Una vez realizado, reiniciando apache recogería los cambios del virtualhost, y creando un phpinfo() podríamos ver si realmente coge las directivas especificadas.

$ vi phpinfo.php

<? phpinfo(); ?>