G A C E T A   D E   L I N U X
...haciendo a Linux un poco más divertido!
Seguridad con SuperGlobales PHP
Por David Lechnyr
Traducción al español por Luis Armando Hernandez Enriquez
el día 27 de Enero 2003, para La Gaceta de Linux

"Evita a las mujeres desconocidas y a las variables temporales." -- Anónimo.

Hace algunos años, mi esposa y yo decidimos ir a esquiar al norte. Para reservar el equipo de esquiar, debías hacerlo 24 horas antes a través del Sitio Web en línea en el apartado de reservaciones de esquís. El asunto fue que mi esposa me pidió hacer las reservaciones 23 horas antes de la hora límite:

De esta manera comencé a pensar que las condiciones del Sitio Web en línea, no me iban a permitir hacer reservaciones si no era dentro de las 24 horas límite en que estaba estructurado el Sitio. Sin embargo, una vez que seleccionas una fecha adecuada, pude percatarme que el URL era:

https://www.somewhere.com/reservations.php?date=01-23-01

Esto me ocurrió mientras ellos habían desbloqueado la seguridad sobre aquellas fechas de las que yo podía escoger, el valor final fue introducido dentro de una sentencia GET al final de la dirección Web. Yo modifiqué la dirección Web para utilizar "date=01-22- 01" y desde luego, nuestros esquís estuvieron esperándonos a primera hora a la mañana siguiente (pagamos por ellos, por supuesto).

Este ejemplo inocente en la práctica, es solo uno de los peligros a los cuáles debemos de estar alertas cuando se utiliza algún lenguaje de programación que pudiera ser usado en formas diferentes a las que llegamos a probar, lo que nos conduce a nuestra discusión sobre las Superglobales PHP.

Formularios

Para entender las Superglobales, es fundamental que entiendas la manera en que los datos son pasados de una página Web a otra (Ej. Los formularios). Específicamente, debes estar consciente de dos métodos conocidos como GET y POST. Probablemente, estés familiarizado con la sentencia

de HTML (una buena referencia es http://www.w3.org/TR/html401/interact/forms.html).

Probablemente hayas visto algo como esto anteriormente:

<form name="form1" method="post" action="process.php">
   <p>Please enter your name:</p>
   <p><input type="text" name="yourname" /></p>
   <p><input type="button" name="Submit" value="Submit" /></p>
</form>

Esto es estándar de código de un formulario HTML que pide algo de información y entonces envía los datos al archivo "process.php".  El punto crítico aquí es la declaración del método (method), que indica la forma en la que serán enviados los datos, la cuál necesitamos discutir por un momento o dos (sostén la respiración):

Para aquellos que recuerdan los primeros días del HTML, los formularios eran provistos por medio de la etiqueta HTML <ISINDEX>. Al insertar esta etiqueta dentro del HEAD de tus documentos HTML, un campo de texto aparecía donde se podía ingresar al llenado del formulario. Así como el nuevo estándar HTML+ evolucionaba, una etiqueta <FORM> fue designada y podía utilizarse con un atributo MÉTODO (METHOD) de las sentencias GET, POST, o PUT.  Así, esto nos permite algunas maneras diferentes para enviar nuestros datos.

GET

Con GET, las variables y sus valores se envían en el encabezado de la solicitud URL apendizada como parte del URL misma.  La limitación es que las direcciones Web (URLs) se limitan a 8,192 caracteres; si la cantidad de datos es demasiado extensa, ésta se truncará. También, aún con una conexión SSL, los datos no se encriptan ya que son parte de la dirección Web.

Por ejemplo, una página Web podría tener una sentencia para formulario como esta:

<form name="form1" method="get" action="process.php">
   <p>Please enter your name, e-mail address, and a comment:</p>
   <p><input type="text" name="yourname" /></p>
   <p><input type="text" name="email" /></p>
   <p><input type="text" name="comment" /></p>
   <p><input type="button" name="Submit" value="Submit" /></p>
</form>

Cuando tú haces click en el botón Submit, tu navegador Web tomaría los valores que tú llenaste dentro del formulario y te redireccionaría a esta dirección Web:

http://www.fluffygerbil.com/process.php?yourname=fred+smith&email=fred@nowhere.com&comment=I+have+no+comment

¿Notas cómo los valores del formulario son parte de la dirección Web en sí misma? Esa es la esencia de GET.

Como dato curioso, lo que realmente se envía en la transmisión HTTP pura para llevar a cabo esta transacción es:

GET /process.php?yourname=fred+smith&email=fred@nowhere.com&comment=I+have+no+comment HTTP/1.0
Accept: image/gif, image/x-xbitmap, image/jpeg, */*
Accept-Language: en-us
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461)
Host: www.fluffygerbils.com
Connection: keep-alive

POST

Con POST, las variables y sus valores son enviados en el cuerpo de la solicitud URL, no en el encabezado (header).  Las ventajas de este tipo de transmisión de datos es que no existe límite para el tamaño de los datos que se envían, ya que está contenido en el cuerpo de la solicitud HTTP, no en el encabezado. También, si estás utilizando una conexión SSL, los datos serán encriptados de igual forma, qué trato. :)   Por ejemplo, una página Web que tiene una sentencia de formulario como:

<form name="form1" method="post" action="process.php">
   <p>Please enter your name, e-mail address, and a comment:</p>
   <p><input type="text" name="yourname" /></p>
   <p><input type="text" name="email" /></p>
   <p><input type="text" name="comment" /></p>
   <p><input type="button" name="Submit" value="Submit" /></p>
</form>

Cuando tú haces click en Submit, tu navegador Web tomaría los valores que escribiste dentro del formulario para redireccionarlos a la dirección Web:

http://www.fluffygerbil.com/process.php

¿Notas cómo los valores del formulario no son parte de la dirección Web en sí misma? Esta es la esencia de PUT.

For the curious, what is actually sent in the raw HTTP transmission to accomplish this transaction is:

De igual manera como dato curioso, lo que realmente se envía en la transmisión HTTP pura para llevar a cabo esta transacción es:

POST /process.php HTTP/1.0
Accept: image/gif, image/x-xbitmap, image/jpeg, */*
Accept-Language: en-us
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461)
Host: www.fluffygerbils.com
Content-Length: 94
Pragma: no-cache
Connection: keep-alive

yourname=fred+smith
email=fred@nowhere.com
comment=I+have+no+comment

¿Y Qué hay con esto?

Y, ¿Por qué es útil toda esta información de fondo? Cuando tú instalas PHP 4.2.2 o versiones posteriores, podrías notar que cuando se compila PHP, éste establece lo siguiente:

+--------------------------------------------------------------------+
|                          *** NOTE ***                              |
|            The default for register_globals is now OFF!            |
|                                                                    |
| If your application relies on register_globals being ON, you       |
| should explicitly set it to on in your php.ini file.               |
| Note that you are strongly encouraged to read                      |
| http://www.php.net/manual/en/security.registerglobals.php          |
| about the implications of having register_globals set to on, and   |
| avoid using it if possible.                                        |
+--------------------------------------------------------------------+

Que significa que PHP se pondrá ultra-paranoico acerca de los datos que le sean pasados, y requerirá establecer el método por el que los datos deberían llegar. También, deberías estar consciente que existen más formas de enviar datos a tus páginas PHP que las tradicionales GET y POST:




Superglobales

Lo que nos lleva a las Superglobales, relativamente un nuevo concepto para PHP. Por ejemplo, el diagrama de arriba presenta un ligero problema: Si estás trabajando con la variable $yourname, ¿cómo sabes si durante la ejecución de tu script, ésta no es redefinida por alguien más mediante alguno de estos seis otros métodos de asignación de variable intentando infiltrarse en tu script? Por ejemplo, imagina que tienes a alguien que ha trabajado en la carga de un script PHP en tu servidor Web que realiza lo siguiente (php exploit by Daniel Phoenix):

<?php
setcookie("test","../../../../../../etc/passwd");
echo "cookie inserted";
?>

¿No sería grandioso tener una forma para aislar las variables basadas en como los datos son asignados a ésta en primer plano? Las Superglobales te permiten especificar qué variables recibidas por un método específico deberían utilizarse.

Las Superglobales son un intento de PHP que te ayudan a determinar de dónde viene un determinado valor. Si no has escuchado de esta nueva característica de PHP 4.1.0, necesitarás comenzar a adaptarte a ella. La mayoría de los libros de capacitación de PHP no hacen referencia a este tema, por lo que deberás estar consciente de cómo vas a hacer la transición a este nuevo método de entrada.  Ultimadamente, deberías volver a visitar tu archivo /usr/local/lib/php.ini y hacer el siguiente cambio:

register_globals = Off

Esto te prevendrá de la variable hábilmente insertada por algún usuario dentro de tu código PHP y podrá reducir la cantidad de variables de atacantes potenciales evitando que pudieran dañarte. Deberán tener el tiempo adicional para forzar las entradas de los Submits, y tus variables internas son efectivamente aisladas de los datos introducidos por el usuario. Si un usuario entonces intentara llenar un formulario, el servidor no le asignaría dato alguno a las variables globales $name, $email, o $comment. En vez de esto, dividiría los datos en los siguientes arreglos mezclados:

$_POST['name']
$_POST['email']
$_POST['comment']

Los principales arreglos Superglobales son:

  1. $_GET['variable'] - Variables proporcionadas al script vía GET HTTP. Semejantemente al arreglo censurado HTTP_GET_VARS
  • $_POST['variable'] - Variables proporcionadas al script vía POST HTTP. Semejantemente al arreglo censurado $HTTP_POST_VARS
  • Los otros arreglos Superglobales, menos comunes son:

    1. $_COOKIE['variable'] - Variables proporcionadas al script vía cookies HTTP. Semejantemente al arreglo censurado $HTTP_COOKIE_VARS
    2. $_REQUEST['variable'] - Variables proporcionadas al script vía cualquier mecanismo de entrada de usuario (GET, POST, COOKIE) , las cuáles no pueden ser aceptadas confiablemente.
    3. $_GLOBALS['variable'] ââ,¬â¤½ Contiene una referencia a cada variable que está actualmente disponible dentro del visor global del script. Las claves de este arreglo son los nombres de las variables globales.
    4. $_SERVER['variable'] - Variables puestas por el servidor Web o como alternative directamente relacionada al ambiente de ejecución de el script actual. Semejantemente al arreglo censurado $HTTP_SERVER_VARS
    5. $_FILES['variable'] - Variables proporcionadas al script vía al cargar archivos HTTP referenciados. Semejantemente al arreglo censurado $HTTP_POST_FILES
    6. $_ENV[variable] - Variables proporcionadas al script vía el ambiente. Semejantemente al arreglo censurado $HTTP_ENV_VARS
    7. $_SESSION[variable] - Variables que son registradas actualmente a la sesión del script. Semejantemente al arreglo censurado $HTTP_SESSION_VARS

    Para más detalles, véase http://www.php.net/manual/en/reserved.variables.php.

    Así, en vez de $name colocada a "John", tendrías $_GET['name'] = "John" o posiblemente $_POST['name'] = "John" dependiendo de cómo fueron enviados los datos del formulario. La ventaja es que sabrás:

    1. $name nunca puede falsificarse; si tu script le fija su valor, ¡ése es su valor!
    2. Los arreglos $_GET y $_POST te ayudan a determinar si el usuario apendizó los datos como parte del URL o como parte del cuerpo de la petición; por lo tanto, no tienes que preocuparte por tener un formulario que aceptando datos POST y tener el cambio de valores por alguien enviando un URL hackeado con datos GET apendizados al URL. Esto tendrá sentido en breve, así que aguante...
    3. Estas 'Superglobales' te permiten 'aislar' no solamente los valores de tus variables, sino como los valores fueron proporcionados al servidor en el primer plano. Alguien intentando infiltrarse dentro de tu servidor tendrá momentos difíciles al pasar esto.

    Ideas Finales

    Programando con PHP puede ser una experiencia frustrante a veces. Las medidas de seguridad previenen a los datos de ser fácilmente asignadas a variables, los ISP's típicamente implementan PHP sin consideración de su audiencia, y los recién entrantes a PHP tienden a dejarse abatir por términos tales como GET, POST, Superglobals, y así por el estilo.

    Sin embargo, un poco de conocimiento puede salvar el camino, y espero que este artículo te haya ayudado en tu búsqueda.

    Este documento fue preparado basado en PHP 4.3.0.

    Recursos Adicionales

    Este documento fue cariñosamente elaborado en una Laptop Dell Latitude C400 bajo Slackware Linux 8.1.

    [BIO] David es un Administrador de Red del Departamento de Recursos Humanos de la Universidad de Oregon. Sostiene una Maestría en Trabajo Social junto con su MCSE+I, CNE, y certificaciones CCNA. Ha trabajado con Linuxlos últimos 6 años, con énfasis en la seguridad de sistemas, en la resolución de problemas de red, y en la integración PHP/MySQL.


    Copyright © 2003, David Lechnyr. Copying license http://www.gacetadelinux.com/en/lg/copying.html
    Publicado en el número 86 de Linux Gazette, Enero 2003