guía de seguridad en php

15
PEQUENÑA GUIÍA DE SEGURIDAD EN PHP Este documento desarrolla unas pequeñas bases para desarrollar sitios con PHP un poco más seguros Elaborado para el curso 2010/2011

Upload: josemaria181159

Post on 29-Jun-2015

142 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Guía de seguridad en PHP

PEQUENÑ A GUIÍA DE SEGURIDAD EN PHP

Este documento desarrolla unas pequeñas bases para desarrollar sitios con PHP un poco más seguros

Elaborado para el curso 2010/2011

Page 2: Guía de seguridad en PHP

2/

15

Tabla de contenido Guía de seguridad en PHP ................................................................................................................................. 3

Introducción .................................................................................................................................................. 3

Objetivo del documento ............................................................................................................................ 3

Cómo leerlo ............................................................................................................................................... 3

Directivas de configuración ........................................................................................................................... 3

Archivos de configuración ......................................................................................................................... 3

Tipos de directivas ..................................................................................................................................... 4

Cómo cambiar directivas del tipo PHP_INI_PERDIR .................................................................................. 4

register_globals ......................................................................................................................................... 5

Buenas costumbres ....................................................................................................................................... 7

error_reporting .......................................................................................................................................... 7

safe_mode ................................................................................................................................................. 8

open_basedir ............................................................................................................................................. 8

Nomenclatura de archivos......................................................................................................................... 9

Errores ......................................................................................................................................................... 10

Mostrar errores según entorno ............................................................................................................... 10

Entornos de desarrollo ............................................................................................................................ 10

Entornos de usuario final......................................................................................................................... 10

Registro de errores .................................................................................................................................. 11

Consejos de seguridad programando en PHP ................................................................................................. 12

1. Validar Formularios ................................................................................................................................. 12

2. Proteger la base de datos ........................................................................................................................ 12

3. Proteger la información de sesiones y cookies ....................................................................................... 13

4. Proteger nuestras aplicaciones de las vulnerabilidades XSS (Cross-site scripting) ................................. 13

5. Proteger nuestros formularios de códigos inválidos ............................................................................... 14

6. Protección contra ataques CSRF (Cross-Site Request Forgeries) ............................................................ 14

7. Proteger nuestra estructura de archivos ................................................................................................. 15

8. Prevenir acceso a archivos de inclusión .................................................................................................. 15

Page 3: Guía de seguridad en PHP

3/

15

Guía de seguridad en PHP

Introducción

Objetivo del documento

El objetivo de este documento es que el programador que lo lea adquiera unas nociones básicas (y no tan básicas) sobre seguridad que pueda aplicar a la hora de hacer sus aplicaciones. La mayoría de temas que aquí se presentan son temas reales, que se producen al no tener el programador tales no-ciones. La mayoría de temas en los que se va a basar el documento están orientados al uso en pági-nas web.

Entiendo como usuario malintencionado aquel que busca en nuestra aplicación fallas de seguridad y las explota por puro aburrimiento, sin ánimo de reportar esos fallos al programador para que puedan ser subsanados (hay gente que lo hace).

La mejor forma de protegerse es no confiar nunca en cualquier valor que no sea fijo. Si no estás seguro de que una variable va a tener el valor que esperas, o que una llamada a unlink() borra el archivo que quieres, asegúrate, pues puede ser por ahí por donde empiece un ataque.

Asegurarse no consiste en ejecutar el script y decir esto funciona como espero, sino que hay que agotar todas las posibilidades de ataque antes de subir tu página al servidor definitivo.

Cómo leerlo

El documento presupone ciertos conocimientos de PHP, y que el lector sea capaz de poner atención al leer, por lo que se pide encarecidamente que, en caso de que la tengas puesta, quites la música y prestes total atención a lo que hay escrito.

Los bloques de código son ejemplos: los habrá que funcionen y que no. Hay ejemplos de lo que hay que hacer, y también de lo que no hay que hacer, todo con el objetivo de que el lector aprenda a arreglar sus errores viendo código de otra persona.

A lo largo de todo el documento se podrán ver ejemplos que presentan fallos de seguridad, debido a una mala configuración de PHP o un mal uso de las llamadas a las variables.

En otros casos verás ejemplos cuyo código tiene en cuenta los principales aspectos de seguridad. Es muy importante que NO copies y pegues directamente estos códigos en tu página. Antes debes comprender todo lo que se explique para poder aplicarlo.

Directivas de configuración

Archivos de configuración

php.ini Archivo de configuración de PHP. Puedes ver que php.ini estás usando con phpinfo (más adelante se explica qué es y cómo usar phpinfo).

httpd.conf En él guarda su configuración el servidor HTTP Apache; al ser este el más utilizado por desarrolladores y servicios de alojamiento (tanto gratuitos como de pago) es en el que se

Page 4: Guía de seguridad en PHP

4/

15

centrarán los comentarios de este documento. Normalmente se encuentra en el directorio conf en el directorio raíz de Apache.

.htaccess Fichero especial que usa Apache en el que se pueden poner ciertas llamadas a sus directivas o las de algunos módulos que haya cargado. Requiere permisos para poder utilizarlo. Más adelante se enseña a comprobar si es posible su uso.

Tipos de directivas

PHP_INI_SYSTEM Las directivas de este tipo se pueden modificar en el php.ini y en el httpd.conf

PHP_INI_PERDIR Las directivas de este tipo pueden cambiarse en los archivos php.ini, httpd.conf y .htaccess. Para saber cómo cambiarlas en archivos .htaccess consulta la siguiente sec-ción.

PHP_INI_USER Según el manual de PHP (en su versión española): La entrada puede definirse en scripts de usuario. Si miramos el manual en inglés (más recomendable, la verdad) veremos que en realidad quiere decir que las directivas pueden ser modificadas en el registro de Windows. Aunque listada en el manual, parece no haber ninguna directiva que sea de este tipo (supon-go que se podrán modificar las de tipo PHP_INI_SYSTEM). Al no ser la mayoría de servi-cios de alojamiento usuarios de Microsoft Windows no explicaré como cambiar estas direc-tivas.

PHP_INI_ALL Estas directivas pueden ser cambiadas en cualquier parte, incluso en el propio script por me-dio de ini_set().

Cómo cambiar directivas del tipo PHP_INI_PERDIR

Lo primero que deberías hacer es obtener información sobre la actual configuración del servidor, mediante el uso de estas líneas.

<?php phpinfo() ?>

La función phpinfo() nos muestra información sobre la configuración de PHP y sobre la máquina en la que está instalado. En la página que genera veremos cómo está ajustado PHP. Es importante fa-miliarizarse con esta función y con su salida, puesto que es básica y se usará muy a menudo.

Antes de explicar cómo cambiar este tipo de directivas debes asegurarte de que tu servidor cumple una serie de requisitos:

PHP como módulo de Apache Es fácil saber si PHP está compilado o instalado como módulo de Apache. Simplemente tie-nes que mirar en el phpinfo() la línea en la que pone Server API tenga un valor como Apa-che 2.0 Handler.

AllowOverride con el valor Options o All Esto es un poco más pesado de comprobar, hay que hacer lo siguiente: pon en un archivo llamado .htaccess en el directorio que tengas la página una cadena como asdasd123. Si Apache muestra un Internal Server Error al actualizar esa página es que tenemos permiso para usarlos.

Page 5: Guía de seguridad en PHP

5/

15

Si cumples estos dos requisitos ya puedes cambiar el valor de register_globals (u otras opciones de configuración de PHP) en el archivo .htaccess del directorio sobre el que queremos aplicar estas reglas (puede que tengas que crearlo):

#Para directivas con valores booleanos (On/Off, 1/0…) se usa php_flag php_flag register_globals Off #Para otras directivas se usa php_value php_value error_reporting 4095

register_globals

No nos engañemos, tener register_globals a on no es inseguro, lo que provoca los fallos de seguri-dad es el no programar bien y el no tener en cuenta a posibles atacantes. Cualquier variable que no definamos, o cualquiera de la que no comprobemos datos puede ser víctima de envenenamiento de variables, aquí voy a exponer un poco que hacer en estos casos.

La comunidad PHP decidió desactivarlo por defecto (antes estaba activado) a partir de la versión 4.2.0.

Esta directiva inicialmente era de tipo PHP_INI_ALL (se podía cambiar con ini_set() en el php.ini o mediante archivos .htaccess), pero a partir de PHP 4.2.3 es de tipo PHP_INI_PERDIR (se puede cambiar solamente desde el php.ini o los archivos de configuración de Apache). Más abajo se explica cómo cambiar valores de configuración con este tipo de archivos.

La razón por la que en algunos de los ejemplos de este documento se usará register_globals a on es para que se vean los peligros que corres si lo tienes activado, y como (en medida de lo posible) sub-sanarlos.

Razones para tenerlo desactivado

Tenerlo activado no hace más insegura una aplicación, ¿pero tenerlo desactivado la hace más segu-ra? Sí, así es. No porque nos vaya a proteger contra los "malvados jakers que comen donuts y piz-za", no es milagroso, pero nos va a forzar a no usar variables globales para referirnos a valores pa-sados por POST, GET, valores de sesión o cookies.

Matrices superglobales ($_GET, $_POST, $_SESSION…)

Mucho se ha hablado de las variables (o matrices) superglobales (las que debes usar para referirte a lo mencionado anteriormente), pero todavía queda gente que, o bien no las conoce, o bien cree que no son necesarias, o que simplemente no las usa por pura pereza, por no modificar su código (aun-que esto le vaya a beneficiar, y mucho). Qué le vamos a hacer, así somos…

A partir de la versión 4.1.0 de PHP están disponibles estas variables, y a partir de YA (si todavía no lo haces) debes usarlas.

La diferencia entre las variables normales (presuponiendo el valor de register_globals activado, que es como lo tienen la mayoría de servicios de alojamiento, gracias a aplicaciones como PHP-Nuke y similares) y las matrices superglobales es muy simple. Usando matrices superglobales no se puede producir envenenamiento de variables normales a través de URL, de cookies falseadas, etc.

La razón de este comportamiento es que register_globals (cuando está activado, obviamente) inyec-ta los valores de las variables que se pasan al script (lo que en esencia sería como usar la función

Page 6: Guía de seguridad en PHP

6/

15

extract() en cada una de las matrices superglobales), esto es terriblemente dañino si no se sopesan las consecuencias. Imaginemos por un momento que nuestro panel de control comprueba que el usuario está acreditado para acceder a él de la siguiente forma (el ejemplo es de PHP.net):

<?php if (usuario_valido()) { $autorizado = true; } if ($autorizado) { echo "Bienvenido a mis documentos importantes\n"; } else { echo "No tienes acceso a esta sección\n"; } ?>

Poquitas líneas, ¿eh? Pues contienen varios fallos… Si te fijas es muy simple resolverlos. Vamos a analizar el código:

if (usuario_valido()) { $autorizado = true; }

Si el usuario es válido definimos la variable $autorizado como true, ¿y si no lo está? ¿no la defi-nimos? Imagina por un momento que acceden a ese documento con la url pa-

nel.php?autorizado=1, ¿qué pasaría? saldría el bonito mensaje de Bienvenido a mis documentos importantes. Recuerda definir siempre las variables que vayas a usar.

El ejemplo anterior, bien programado sería algo parecido a esto:

<?php if (usuario_valido()) { //Podemos guardar información útil $_SESSION['autorizado'] = 'Nombre del usuario'; } else { $_SESSION['autorizado'] = false; } //$_SESSION['autorizado'] va a estar siempre definida if ($_SESSION['autorizado'] !== false) { echo "Bienvenido a mis documentos importantes {$_SESION['autorizado']}\n"; } else { echo "No tienes acceso a esta sección\n"; //Finalizamos la ejecución de la aplicación, no nos interesa que se siga in-terpretando código exit; } ?>

Qué hacer cuando se tiene activado

Puedes intentar desactivarlo usando el método que se explica más arriba. De todas maneras, si pro-gramas bien una aplicación (como se detalla en la siguiente sección) es improbable que tener esta directiva activada te afecte en demasía, así que no te preocupes.

Page 7: Guía de seguridad en PHP

7/

15

Buenas costumbres

A continuación tienes una lista de cosas que debes tener en cuenta:

• Definir siempre las variables antes de usarlas. • Usar matrices superglobales en tus aplicaciones, en detrimento de las antiguas globales. • No usar nombres típicos para las variables, ya que aumentas la posibilidad de que un atacan-

te descubra como modificarlas.

error_reporting

Esta directiva, aunque extraordinariamente útil, puede llevar a nuestro atacante a conocer datos so-bre nuestras aplicaciones, por lo que distinguiremos dos entornos: el entorno de desarrollo y el en-torno de usuario final. Se explicará en que consiste cada una en su correspondiente sección.

error_reporting (tanto la directiva como la función) admiten como parámetro un número entero. Puedes usar las constantes numéricas que provee PHP para el control de errores y combinarlas con operadores bit a bit en el archivo php.ini y en tus aplicaciones, pero no en los archivos httpd.conf o .htaccess.

Los valores por defecto son los siguientes:

PHP 3 El valor por defecto es 7, lo que equivale a E_ERROR | E_WARNING | E_PARSE, pero dado que en PHP 3 no se soportaban las constantes en el archivo php3.ini el valor había de ser numérico.

PHP 4 y PHP 5 E_ALL & ~E_NOTICE. Se muestran todos los errores salvo los de tipo E_NOTICE y E_STRICT (este último solo es aplicable a PHP 5).

Las constantes predefinidas dedicadas al manejo de errores que usaremos habitualmente son estas:

E_ERROR Errores fatales al ejecutar una aplicación, interrumpen la ejecución del mismo. Estos errores se producen por ejemplo al intentar utilizar funciones no definidas.

E_WARNING Advertencias en tiempo de ejecución, no detienen la ejecución de una aplicación. Se produ-ce cuando (por ejemplo) se proporciona a una función (como fwrite()) un recurso no válido como parámetro.

E_NOTICE El tipo menos conocido, junto con E_STRICT, y de los más útiles. Estos errores se producen mayormente al encontrar el intérprete de PHP una variable o constante no definida. No de-tienen la ejecución.

E_ALL Agrupa todos los errores excepto los de tipo E_STRICT.

E_STRICT Está disponible únicamente a partir de PHP 5. Si habilitas este tipo de error PHP lanzará avisos si encuentra código obsoleto para que el programador (o sea, tú) puedas corregirlo y así mantener la compatibilidad e interoperabilidad.

Cada una de estas constantes tiene un valor numérico, puedes ver el valor de cada una imprimiendo la constante en cuestión.

Page 8: Guía de seguridad en PHP

8/

15

Como este tema tiene bastante miga se va a explicar en una sección aparte.

safe_mode

Es de tipo PHP_INI_SYSTEM y está desactivada por defecto.

Esta directiva es, según el manual de PHP, un intento para resolver el problema de la seguridad en un servicio de alojamiento compartido (el más común, poca gente puede permitirse un servidor de-dicado).

Básicamente lo que hace esta directiva al estar activada es comprobar que los ficheros sobre los que operamos desde otro fichero (la aplicación) tienen el mismo dueño (en sistemas UNIX).

Veamos un ejemplo de esto (que puede sonar perfectamente a chino, no te preocupes):

$ ls -l -rw-r--r-- 1 root root 36 2005-04-09 03:02 fichero1.php -rw-r--r-- 1 aeoris aeoris 73 2005-04-09 03:02 fichero2.php

Como se puede ver el archivo con nombre fichero1.php pertenece al superusuario (o root) y el fichero2.php a aeoris, ahora veamos qué pasa si intento leer el contenido de fichero1.php desde el archivo que me pertenece (fichero2.php) teniendo safe_mode activado.

Warning: file_get_contents(): SAFE MODE Restriction in effect. The script whose uid is 1000 is not allowed to access fichero1.php owned by uid 0 in /var/www/fichero2.php

Al no tener los mismos dueños se produciría un error.

Esto en un momento dado nos podría proteger contra otros usuarios del mismo alojamiento que, por ejemplo, quieran obtener datos sobre nuestras aplicaciones. En el momento en que intentasen hacer-lo no podrían.

Pero… no podrían con PHP… con cualquier lenguaje es una cosa trivial hacer un explorador de archivos del sistema sencillito, con lo que puede ver donde están nuestros archivos, y en la mayoría de casos (al no estar en PHP y no tener safe_mode) visualizar el código fuente.

Mi consejo con este tema es que no confíes demasiado en esta directiva, pues no te protege en abso-luto. Suele ser más molesta que útil (es mi opinión, no ha de tomarse como un referente).

Teniéndola activada también se restringirán algunas funciones, hay una lista de estas funciones en el manual de PHP que los mismos escritores definen como posiblemente incorrecta e incompleta.

open_basedir

Es de tipo PHP_INI_SYSTEM y tiene valor nulo por defecto.

Lo que hace es limitar el espacio de trabajo al directorio al que está ajustada la directiva. Si quisié-ramos incluir un fichero por encima de ese directorio lanzaría un error.

Veamos un ejemplo (teniendo en cuenta que open_basedir vale /var/www):

Page 9: Guía de seguridad en PHP

9/

15

<?php readfile('/etc/resolv.conf'); ?>

Produciría este error:

Warning: readfile(): open_basedir restriction in effect. File(/etc/resolv.conf) is not within the allowed path(s): (/var/www/) in /var/www/open_basedir.php on line 3

Este tipo de error normalmente se ve al usar la función copy() para mover archivos que se han subido con un formulario. Este comportamiento es erróneo y debería usarse move_uploaded_file() en su lugar.

Esta directiva puede ser útil en un momento dado, pero por lo general dará quebraderos de cabeza innecesarios.

Nomenclatura de archivos

Este es un tema un poco retorcido: ¿a qué me refiero con nomenclatura de archivos? Simplemente al nombre que se les pone a los archivos o directorios (que no son más que archivos que a su vez contienen otros archivos).

Un hacker intentará encontrar el nombre del archivo que contiene datos tales como la contraseña de la base de datos o la contraseña de acceso al panel de control, datos con los que pueda causar un daño, o simplemente probar la seguridad de una aplicación.

Intenta no poner fácil que se averigüen los nombres de los archivos. Con esto quiero decir que no le pongas al panel de administración como nombre admin.php o cpanel.php (si, esto también es aplicable si los tienes en directorios a parte…).

He visto gente que le pone extensión .inc (por include supongo) a sus aplicaciones programadas en PHP. Esto es terriblemente peligroso. Accediendo a la URL del archivo en el que tengas la co-nexión a la base de datos por ejemplo tendrían los datos para conectar, con lo que podrían borrarla en un momento dado.

He visto casos de páginas muy importantes y que la mayoría usamos mucho que nombraban a sus archivos con extensiones de este tipo, con lo que obtener el código y hacer un volcado de la base de datos (nombres de usuario, contraseñas, números de tarjeta de crédito…) no resultaría nada difícil.

Estos dos últimos párrafos vienen a decir que no debes poner bajo ningún concepto extensiones que no interprete PHP por defecto a tus aplicaciones.

Si no quieres cambiar la extensión (¿demasiado trabajo quizá?) te recomiendo que vetes el acceso a estos archivos de forma directa, puedes poner el siguiente código en un archivo .htaccess (aunque depende de que tu servidor sea Apache, de que puedas usar .htaccess…):

<FilesMatch "\.inc$"> Order allow,deny Deny from all </FilesMatch>

Las mismas reglas que se explican arriba sobre no poner nombres típicos a los archivos se aplican a los directorios.

Page 10: Guía de seguridad en PHP

10/

15

Debes cuidar de tener una estructura de directorios limpia y clara de tu aplicación, para trabajar más cómodamente con ella. Esto no significa que debas descuidar los nombres de los directorios; puedes poner un número aleatorio delante del nombre de cada uno para así mantenerlas más o menos fuera del alcance de ciertos elementos.

Errores

Ya se ha hablado un poco de como los errores son mostrados (o no) por PHP; se ha dicho que, cuando la aplicación se encontraba en el servidor público, la mejor opción era ocultar al usuario los errores lanzados por el intérprete y ofrecerle unos más amigables y porque no, carecientes de infor-mación relativa al servidor. Como se puede suponer, esto es bueno, pero carece de utilidad real si no sabemos siquiera que esos errores han existido. Debemos ser informados si ocurren, y esto obvia-mente no lo podemos dejar en manos del usuario.

Mostrar errores según entorno

Dependiendo de donde tengamos alojada la página (en un servidor local o en uno final) deberemos mostrar o no los errores. Antes de que subas la página debes limar la mayoría de asperezas que pueda tener, aquí verás cómo tener bien configurado el reporte de errores.

Entornos de desarrollo

En estos casos nos interesa que se muestren absolutamente todos los errores, puesto que nos ayu-darán a corregir posibles fallas de seguridad (como que no definimos una variable por ejemplo) entre otras cosas.

PHP, como hemos visto antes, ajusta a un valor por defecto la directiva error_reporting, tenemos dos opciones para cambiarla (supongamos que estás en un servidor local, por tanto tienes acceso a todos los ficheros de configuración):

Cambiar la configuración en el php.ini Esta es la solución más fácil, y también la mejor. En el archivo php.ini localiza la línea del error_reporting y cambia su valor por E_ALL | E_STRICT (si usas PHP 5) o E_ALL si usas PHP 4.

Usar la función error_reporting() Esta solución es bastante pesada, por lo que no la recomiendo. Se trata de llamar a la fun-ción error_reporting() en cada uno de los archivos en los que queramos ajustar el reporte de errores. Debes llamarla con los parámetros con los que se ajustaría la directiva error_reporting (mira el punto anterior).

Entornos de usuario final

Ten siempre en cuenta al usuario, ¿qué leches le importa que no puedas conectar a la base de datos? ¿o que haya un error de tipo sintáctico? Absolutamente nada. También debes considerar que un usuario malicioso podría intentar forzar a que hubiese errores, consiguiendo de esta manera infor-mación que le fuese útil a la hora de intentar vulnerar la seguridad de nuestra aplicación.

¿Qué se puede hacer para remediarlo? Simple. Con las mismas que antes (en el punto anterior, en nuestro servidor local) hacíamos que se mostrasen todos los errores aquí nos interesa que no se muestre ninguno.

Page 11: Guía de seguridad en PHP

11/

15

Para ello haremos uso de otra directiva de PHP, diferente de error_reporting, se trata de dis-play_errors().

Esta directiva es del tipo PHP_INI_ALL, por lo que puedes cambiarla usando ini_set(). Si eliges cambiarla de este tipo debes llevar cuidado, ya que si se produce un error fatal se mostrará (ya que el ini_set() nunca llegará a ejecutarse, puesto que se ha terminado la ejecución antes de empezar a interpretarlo). A estas alturas ya conoces como cambiar los valores de las directivas de otras for-mas.

Pero… y si se produce un error, ¿cómo nos enteraríamos? ¡Sigue leyendo!.

Registro de errores

Está claro que no todos los errores tienen el mismo impacto en la página, uno por ejemplo puede hacer que salga mal una letra, y otro que una sección no se muestre. Es por ello que debemos ser informados de todos los errores que ocurran en nuestra página, desde el más insignificante hasta los más graves.

PHP dispone de varias maneras de registrar los errores, la más común es usar el registro del sistema en sistemas UNIX (syslog) ajustando esto desde el propio php.ini, aunque no es recomendable, pues no tendremos acceso a este fichero, ya que está restringido al superusuario. Pasamos a explicar una forma correcta, aunque restrictiva (requiere Apache y poder usar ficheros .htaccess) de cazar hasta los errores de interpretación (aunque estos, en teoría, jamás deberían estar presentes en el ser-vidor).

Tenemos que decirle a PHP tres cosas:

• Que no muestre los errores. • Que los registre. • Un sitio donde registrarlos.

Ahora bien, ya se ha dicho que si lo hacemos en la misma aplicación y se produce un error de los que paran la ejecución esto no nos serviría de nada, por eso debemos añadir al .htaccess lo si-guiente:

php_flag display_errors Off php_flag log_errors On php_value error_log "Ruta al registro"

En la tercera instrucción has de poner la ruta completa, a ser posible fuera del directorio visible por el usuario, de un archivo en el cual poner los errores.

Tenemos otro método, que puede usarse para casos puntuales: mandar correos electrónicos. Esto debe ser usado para avisarnos de que la base de datos no conecta, por ejemplo, o que una consulta SQL ha fallado. Nos serviremos de la función mysql_error() para mostrar este caso concreto:

<?php mysql_connect(/* datos de conexión varios*/) || ( mail('[email protected]', 'Fallo al conectar a la base de datos', "MySQL ha devuelto lo siguiente:\n" . mysql_error()) && die("<p>Estamos experimentando problemas, vuelva luego</p>\n")); ?>

Page 12: Guía de seguridad en PHP

12/

15

Consejos de seguridad programando en PHP

1. Validar Formularios

Es sumamente importante validar todos y cada uno de los inputs que recibimos por medio de un formulario web. No solo si el input está vacío, sino también, validar el tipo de dato. Por ejemplo, validar que un campo de email tenga el formato especifico validando el carácter “@” y que conclu-ya con .ext. De igual forma, si pedimos edad o un número validar que el input sea un entero, etc.

Esta validación la podemos hacer con php a nivel de validación por eventos con php y utilizando Javascript de igual forma.

Otro punto es validar la información que viene de un formulario a partir de una sesión determinada para evitar recibir doble posting de datos o simplemente evitar que alguien se le ocurra darle varias veces al botos de enviar. Una solución recomendable es utilizar recapcha, propia o de un tercero como recapcha de google.

Otra forma sería utilizando tokens, por ejemplo:

<?php //preguntamos si el token enviado es igual al que tenemos en sesión if ($_SESSION['token'] == $_POST['token']) { //procesamos formulario } else { //enviamos un mensaje de alerta o simplemente direccionamiento } //creamos la variable token con calor encriptado $token = md5(uniqid(rand(), true)); //creamos una variable de session con el valor generado $_SESSION['token'] = $token; ?> <form id=”myForm” action=”<?php echo $_SERVER['PHP_SELF']; ?>” method=”post”> <div><input type=”hidden” name=”token” value=”<?php echo $token; ?>” /> <input type=”text” name=”myText” value=”<?php echo(isset($_POST['myText']) ? $_POST['myText'] : ''); ?> ”/> <input type=”submit” value=”Save” name=”submit” /> </div>

</form>

Como vemos el truco es enviar el valor como valor del array _POST para ser comparado como va-lidación para el procesamiento de formulario. Sencillo verdad!

2. Proteger la base de datos

Cuando hablamos de proteger la base de datos, hablo en sentido de programación. Digo esto por-que, si bien he visto en práctica que algunos cuando estamos realizando consultas en las bases de datos lo hacemos directamente insertando el valor que viene por un campo de un formulario de bús-queda o de registro de información y no procesamos ese valor antes de utilizarlo en la consulta o query, sino que se utiliza de manera directa.

Por ejemplo:

$select = “SELECT * FROM news WHERE newsid = ‘”. $_POST['id'].”‘”;

Page 13: Guía de seguridad en PHP

13/

15

Esto es una mala utilización de las variables dentro de las consultas. Lo indicado es procesar la va-riable antes de utilizarla en la query. Una recomendación sencilla seria esto:

//limpiamos la variable captada mediante _POST $var1= mysql_real_escape_string($_POST['id']); //Ahora utilizamos la variable limpia $select = “SELECT * FROM news WHERE newsid = ‘”.$var1.”‘”;

Para manejo de variables con valores string también debemos tener en cuenta addslashes. Véase http://www.php.net/manual/en/security.php para ampliar sobre estas técnicas.

3. Proteger la información de sesiones y cookies

Cuando trabajamos con aplicaciones y páginas que requieren algún tipo de autenticidad como sis-temas de foros, áreas exclusivas, etc. es necesario tener los valores de sesión o de cookie para man-tener al usuario validado constantemente mientras navegas por las áreas restringidas. El uso de se-siones y cookies es lo más común por ahora, donde almacenamos los datos como usuario, clave, no. de cuenta etc. para permitirnos no solo autenticar al usuario constantemente y mantenerlo activo, sino también para ahorrarnos hacer querys o consultas sencillas cuyos resultados podemos manejar de otra forma y ahorrar tiempo, código y recursos del servidor.

Ojo con eso. He visitado sitios donde una vez creada una cuenta como miembro, proceso a verificar el archivo de sesión físico, y me encuentro con que está registrada en sesión mi nombre de usuario, mi clave – sin encriptar, mi record completo incluyendo mi correo electrónico, edad, etc.

Existen sitios donde una vez creada una cuenta como miembro, al verificar el archivo de sesión, se encuentra almacenada en él todo el registro completo del usuario autentificado, incluida la password y sin codificar …

Esto no debe hacerse de ninguna forma, las sesiones o cookies deben ser únicamente para validar y almacenar variables globales que son necesarias en nuestros sistemas sin que pongan en riesgo la información del usuario.

Recomiendo encriptar toda la información que se pueda y nunca, pero nunca almacenar el registro completo o perfil de un usuario. Otra alternativa es almacenar la sesión en la base de datos y por supuesto, usar la función session_set_save_handler() de php para mejorar aún más la seguridad y control.

4. Proteger nuestras aplicaciones de las vulnerabilidades XSS (Cross-site scripting)

Cuando hablamos de XSS me refiero a la vulnerabilidad de nuestros sitios de permitir la inserción de código html o sql en nuestras páginas. Por ejemplo, en un sistema que permita comentarios y que no filtre los tags html podría ocasionar que alguien puede insertar un javascript que cree un pop up hacia su sitio en el mejor de los casos.

Para evitar esto debemos retomar la sugerencia No. 1 de este texto y controlar los caracteres espe-ciales que permitimos en nuestros formularios.

Una forma sencilla pero eficaz es utilizar la función php htmlentities() antes de imprimir o presen-tar un valor adquirido por formulario. Por ejemplo:

En vez de esto:

Page 14: Guía de seguridad en PHP

14/

15

echo $_POST['myText'];

Hacemos esto:

echo htmlentities($_POST['myText']);

5. Proteger nuestros formularios de códigos inválidos

De nuevo, hacemos referencia a la sugerencia No. 1 de este texto, y nos vamos aún más allá. En ocasiones no es suficiente con validar nuestros campos en los formularios, sino que, también es recomendable evitar esos caracteres especiales que a veces se filtran haciendo copy/paste, desde ms word por ejemplo. Los cuales causan un total desorden en cuanto a texto plano se refiere.

Esto debe evitarse a toda costa. El ejemplo más común es el de comillas simple o ” ‘ “, la cual apa-rece casi siempre en algún texto en ingles u otro idioma que emplea estos caracteres. Otro caso es de las diéresis, etc. Lo que debemos convertir estos caracteres en código html:

Para evitar, la comillas simple utilizamos la función php addslashes() para evitar que nuestro siste-mas presenten error con estos caracteres:

<?php $str = “Tu nombre es O’reilly?”; // Salida: Tu nombre es O\’reilly? echo addslashes($str); ?>

6. Protección contra ataques CSRF (Cross-Site Request Forgeries)

Cuando hablamos de CSRF, hablamos de la complicidad de nuestros usuarios para con los ataques de sujetos caprichosos o simplemente curiosos. Se presenta cuando pasamos valores mediante url para luego ser utilizados como fuente de referencia para consultas de sql, valor de funciones, etc.

Si bien un usuario puede utilizar una sesión para ser validado y navega nuestro sitio, luego se des-conecta o cierra la sesión, aun así el histórico del navegador almacena los url que hemos visitado. Para evitar que sea desplegada información crítica debemos asegurar que nuestro sistema siempre valide la sesión antes de presentar la información.

También, evitar la utilización de valores de array _REQUEST para información crítica. Ejemplo simple:

En vez de esto:

<?php if ($_REQUEST['submit'] == ‘Save’) { echo(“<p>Estoy procesando tu texto: ”); echo(htmlentities($_REQUEST['text'])); echo(“</p>”); } ?>

Hacemos esto:

<?php if ($_POST['submit'] == ‘Save’) { echo(“<p>Estoy procesando tu texto: ”);

Page 15: Guía de seguridad en PHP

15/

15

echo(htmlentities($_POST['text'])); echo(“</p>”); }

?>

Véase la llamada a la sugerencia No. 4 al desplegar el valor de la variable.

7. Proteger nuestra estructura de archivos

Al referirme a proteger el sistema de archivos, me refiero a la estructura de las carpetas de nuestro servidor web a la hora de diseñar la estructura física de nuestros sitios web y/o aplicaciones.

Es importante que las carpetas que contienen archivos de imágenes y que no deseamos que sean visualizados fuera de nuestro entorno o de nuestra página o aplicación sean ocultadas mediante permisos del servidor o bien mediante htaccess.

Cuando no tenemos control del servidor, ni menos de poder utilizar ficheros .htaccess un simple archivo index.html, index.htm, default.html, o cualquiera que sea nuestro directory index ayuda considerablemente la seguridad de los archivos de forma sencilla. Es muy eficaz para carpetas que contienen archivos de tipo include como vistas, paneles, funciones, librerías, etc.

8. Prevenir acceso a archivos de inclusión

Hoy día es muy popular la utilización de AJAX para mejorar la experiencia del usuario, pero cuida-do, esto requiere la utilización de muchos archivos includes y de remote call en paneles y data grids. Es importante que estos archivos de inclusión no sean vistos directamente. Ejemplo de esto es, si tenemos un archivo llamado main.php otro profile.php y otro extra.php los cuales son incluidos por llamadas desde index.php entonces debemos asegurar los archivos a ser llamados por in-dex.php para que solo este o a través de este pueda verse su contenido.

Para lograr esto hacemos lo siguiente:

En nuestro archivo index.php agregamos la siguiente línea de código:

//declaramos una constante para controlar quien puede o no ver los includes <?php define(‘APPLICATION’, true); ?>

En los archivos main.php, profile.php y extra.php que son los archivos a incluir agregamos esta línea:

<?php if(!defined(‘APPLICATION’)) exit; ?>

Así de simple podemos asegurar todos archivos de inclusión en nuestras aplicaciones web.

Esta guía es una introducción o guía básica de seguridad para programadores PHP. Para más infor-mación y consejos avanzados refiéranse a http://www.php.net/manual/es/security.php.

Fuente de referencia: http://www.ibm.com/developerworks/opensource/library/os-php-secure-apps/index.html