En esta entrada vamos a ver unos cuantos puntos que nos servirán para securizar PHP en nuestro servidor web. Nos centramos en la configuración propia de PHP, hay que tener en cuenta que la securización de la capa aplicación es tanto o más importante que la de la configuración del servidor. Hay que tener siempre actualizados a la última versión estable y con los parches de seguridad correctamente aplicados cualquier cms o script de terceros tipo WordPress, Joomla, Oscommerce, etc.
Ocultar la versión de PHP
En su día hice un artículo completo sobre esto, podéis verlo aquí (ocultar la versión de PHP). Básicamente evitamos que con un simple telnet puedan averiguar la versión de PHP que hay corriendo en el servidor:
# telnet servidor 80 Connected to xxx.com (xx.xx.xx.xx). Escape character is '^]'. HEAD / HTTP/1.0 HTTP/1.1 200 OK Date: Fri, 13 Aug 2010 14:18:09 GMT Server: Apache/1.3.26 (Unix) mod_gzip/1.3.26.1a PHP/5.3.3 Last-Modified: Fri, 12 Feb 2010 12:22:56 GMT ETag: "44967c-6f-53ca4800" Accept-Ranges: bytes Content-Length: 111 Connection: close Content-Type: text/html Connection closed by foreign host.
Para evitar esto cambiamos a off la siguiente variable en el fichero de configuración general php.ini:
expose_php Off
Deshabilitar funciones peligrosas
También hice un artículo hace un tiempo: PHP: Deshabilitar funciones peligrosas. Existen funciones que en servidores con aplicaciones estándar rara vez se usan, pero que por contra pueden generar graves problemas de seguridad si el atacante consigue utilizarlas. Es preferible desactivar el mayor número posible y en caso de que una de ellas sea necesario valorar su activación o proponer alternativas.
Las funciones a deshabilitar se añaden en la directiva «disable_functions» en el fichero php.ini. Aquí tenéis un ejemplo con funciones peligrosas que conviene desactivar:
disable_functions = «apache_child_terminate, apache_setenv, define_syslog_variables, escapeshellarg, escapeshellcmd, eval, exec, fp, fput, ftp_connect, ftp_exec, ftp_get, ftp_login, ftp_nb_fput, ftp_put, ftp_raw, ftp_rawlist, highlight_file, ini_alter, ini_get_all, ini_restore, inject_code, mysql_pconnect, openlog, passthru, php_uname, phpAds_remoteInfo, phpAds_XmlRpc, phpAds_xmlrpcDecode, phpAds_xmlrpcEncode, popen, posix_getpwuid, posix_kill, posix_mkfifo, posix_setpgid, posix_setsid, posix_setuid, posix_setuid, posix_uname, proc_close, proc_get_status, proc_nice, proc_open, proc_terminate, shell_exec, syslog, system, xmlrpc_entity_decode»
O un ejemplo más conservador:
disable_functions ="system,passthru,escapeshellarg,escapeshellcmd,proc_close,proc_open,ini_alter,popen,show_source,pcntl_exec"
deshabilitar session ID en URL
Si queremos que las URL’s de nuestros sitios PHP no muestren los ID de sesiones:
http://ejemplo.com/?PHPSESSID=4kgj577sgabvnmhjgkdiuy1956if6ska
Modificamos la directiva siguiente en el fichero php.ini:
session.use_trans_sid = off
Deshabilitar register_globals
Pese a ser una directiva antigua y que se encuentra en periodo de extinción todavía quedan desarrolladores/programadores que la utilizan. Esta función permite al atacante manipular cualquier variable global definida en la programación. Por defecto está deshabilitada en las versiones actuales de PHP, pero conviene revisarlo por si en algún momento se ha activado:
register_globals = Off
Desactivar acceso a URL remotas en funciones de manejo de ficheros
Funciones como include, fopen o file_get_contents permiten, además de hacer llamadas a ficheros locales, llamar a ficheros vía URL, esto puede provocar graves errores de seguridad invocando a scripts maliciosos que se encuentran fuera de nuestro servidor y su ejecución remota.
Para deshabilitarlo modificamos la directiva allow_url_fopen a Off en el php.ini:
allow_url_fopen = Off
Evitar el acceso a la información de PHP
Como ya sabéis con un simple script como el siguiente podemos ver vía URL toda la información de PHP, su compilación, sus módulos activados, versión, directivas de configuración, etc.
<? phpinfo() ?>
Si queremos desactivarlo, únicamente hay que modificar a Off la siguiente directiva en el fichero php.ini:
expose_php = Off
Si en algún momento necesitáis conocer alguna información, siempre podéis averiguarla desde línea de comandos: información sobre PHP desde línea de comandos
Safe Mode
safe_mode = On
Si bien por defecto safe_mode On puede significar una restricción demasiado fuerte en determinados entornos, puede ayudar mucho a incrementar la seguridad de nuestro servidor. Activar safe_mode implica que los scripts PHP únicamente pueden acceder a los ficheros que tienen como propietario el mismo que ellos. De este modo evitamos por ejemplo que tengan acceso de lectura a ficheros de sistema como /etc/passwd entre otros.
Efectivamente, esto puede ser un problema en el momento que necesitamos acceder a información generada por otros usuarios en el sistema (ficheros de otras aplicaciones. La solución es la siguiente:
safe_mode = Off safe_mode_gid = On
Activamos safe_mode_gid en lugar de safe_mode, de modo que en lugar de revisar el usuario se revisa el grupo. Independientemente del UID del fichero, necesitaremos que estar dentro del grupo para poder acceder al ficheros. El grupo del script PHP deberá ser el mismo que el del fichero a acceder.
Otro punto a tener en cuenta con safe_mode es que no podremos ejecutar binarios. Únicamente aquellos que ubiquemos en el directorio especificado en la configuración:
safe_mode_exec_dir = /directorio
Esto se solaparía con las funciones deshabilitadas anteriormente, como por ejemplo system() o exec().
open_basedir
open_basedir = /directorio
La directiva open_basedir permite configurar que PHP pueda acceder únicamente a los ficheros de un único directorio (y sus subdirectorios). Es una buena forma de enjaular PHP si realmente sólo necesitamos que acceda a un determinado directorio.
Visualización y registro de errores
display_errors = Off log_errors = On error_log = /ruta/fichero/log
Con estas tres directivas, evitamos que cualquier error o warning se muestre por pantalla y hacemos que se registren directamente en un log especificado. De este modo podemos evitar que se muestre información sensible por pantalla. También podéis hacer uso de la directiva error_reporting si queréis mostrar por pantalla los errores. Con ella podéis especificar que se muestren únicamente los warning, los notice o lo que queráis.
SQL Injection
En su día se utilizaba magic_quotes para limpiar los datos de entrada de un script PHP, pero es una directiva obsoleta a partir de PHP 5.3 así que no merece la pena hablar de ella. En su defecto, si usáis servidor web Apache, os recomiendo encarecidamente configurar mod_security y habilitar sus reglas que permiten detectar y parar una gran cantidad de ataques de este tipo, y sino, puedes crear tus propias reglas.
Como último apunte, conviene siempre si es posible mantener una versión estable de PHP, libre de bugs y fallos de seguridad. Seguro además que una vez aplicados estos trucos os toca lidiar con los programadores. Se quejarán de algo seguro ;)