PHP está sujeto a la seguridad misma de la mayoría
de sistemas de servidores en lo que a permisos sobre archivos y
directorios se refiere. Esto le permite controlar cuáles
archivos en el sistema de archivos pueden ser leídos. Debe
tenerse cuidado con aquellos archivos que tengan permisos de
lectura globales, para asegurarse de que su contenido es seguro y
no represente peligro el que pueda ser leído por todos los
usuarios con acceso al sistema de archivos.
Ya que PHP fue diseñado para permitir acceso al nivel de
usuarios al sistema de archivos, es completamente posible escribir
un script PHP que le permita leer archivos del sistema como
/etc/passwd, modificar sus conexiones tipo ethernet, enviar
trabajos de impresión masivos, etc. Esto tiene algunas
implicaciones obvias, en el sentido en que usted tiene que
asegurarse de que los archivos desde lo que lee y hacia los que
escribe datos, sean los correctos.
Considere el siguiente script, en donde un usuario indica que
quisiera eliminar un archivo ubicado en su directorio
personal. Este caso asume que se trata de una situación en
donde se usa normalmente una interfaz web que se vale de PHP para
la gestión de archivos, así que el usuario de Apache
tiene permitido eliminar archivos en los directorios personales de
los usuarios.
Ejemplo 26-1. Un chequeo pobre de variables nos lleva a...
<?php // eliminar un archivo del directorio personal del usuario
$nombre_usuario = $_POST['nombre_enviado_por_el_usuario']; $directorio = "/home/$nombre_usuario";
$archivo_a_eliminar = "$archivo_de_usuario";
unlink ("$directorio/$archivo_de_usuario");
echo "¡El archivo $archivo_a_eliminar ha sido eliminado!"; ?>
|
|
Ya que el nombre de usuario es enviado desde un formulario de
usuario, cualquiera puede enviar un nombre de usuario y archivo
propiedad de otra persona, y eliminar archivos. En este caso,
usted querrá usar otro método de
autenticación. Considere lo que sucede si las variables
enviadas son "../etc/" y "passwd". El código entonces se
ejecutaría efectivamente como:
Ejemplo 26-2. ... un ataque al sistema de archivos
<?php // elimina un archivo de cualquier parte del disco duro al que el // usuario de PHP tiene acceso. Si PHP tiene acceso de root:
$nombre_usuario = "../etc/"; $directorio = "/home/../etc/";
$archivo_a_eliminar = "passwd";
unlink ("/home/../etc/passwd");
echo "¡El archivo /home/../etc/passwd ha sido eliminado!"; ?>
|
|
Hay dos importantes medidas que usted debe tomar para prevenir
estas situaciones.
Aquí hay una versión mejorada del script:
Ejemplo 26-3. Un chequeo de nombres de archivos más
seguro
<?php // elimina un archivo de cualquier parte del disco duro al que el // usuario de PHP tiene acceso.
$nombre_usuario = $_SERVER['REMOTE_USER']; // uso de un mecanismo de // autenticacion
$directorio = "/home/$nombre_usuario";
$archivo_a_eliminar = basename("$archivo_de_usuario"); // remover rutas unlink ($directorio/$archivo_a_eliminar);
$fp = fopen("/home/registros/eliminacion.log","+a"); // registrar el proceso
$cadena_de_registro = "$nombre_usuario $directorio $archivo_a_eliminar";
fwrite ($fp, $cadena_de_registro); fclose($fp);
echo "¡El archivo $archivo_a_eliminar ha sido eliminado!"; ?>
|
|
Sin embargo, incluso este caso no está libre de
problemas. Si su sistema de autenticación le ha permitido a
los usuarios la creación de sus propios nombres en el
sistema, y un usuario elige "../etc/", el sistema se encuenrta
nuevamente expuesto. Por esta razón, puede que uster
prefiera escribir un chequeo más personalizado:
Ejemplo 26-4. Chequeo de nombres de archivos aun más
seguro
<?php $nombre_usuario = $_SERVER['REMOTE_USER']; // uso de un mecanismo de // autenticacion
$directorio = "/home/$nombre_usuario";
if (!ereg('^[^./][^/]*$', $archivo_de_usuario)) die('nombre de archivo inválido'); // finalizar, // no ejecutar el proceso
if (!ereg('^[^./][^/]*$', $nombre_usuario)) die('nombre de archivo inválido'); // finalizar, // no ejecutar el proceso
//etc... ?>
|
|
Dependiendo de su sistema operativo, existe una amplia variedad de
archivos sobre los que usted debería estar atento,
incluyendo las entradas de dispositivos (/dev/ o COM1), archivos
de configuración (archivos /etc/ y los archivos .ini),
areas conocidas de almacenamiento de datos (/home/, Mis
Documentos), etc. Por esta razón, usualmente es más
sencillo crear una política en donde se prohíba toda
transacción excepto por aquellas que usted permita
explícitamente.