|
|
 |
CapÃtulo 26. Seguridad del sistema de archivos
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
$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
$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
$nombre_usuario = $_SERVER['REMOTE_USER']; $directorio = "/home/$nombre_usuario";
$archivo_a_eliminar = basename("$archivo_de_usuario"); unlink ($directorio/$archivo_a_eliminar);
$fp = fopen("/home/registros/eliminacion.log","+a"); $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']; $directorio = "/home/$nombre_usuario";
if (!ereg('^[^./][^/]*$', $archivo_de_usuario))
die('nombre de archivo inválido'); if (!ereg('^[^./][^/]*$', $nombre_usuario))
die('nombre de archivo inválido'); ?>
|
|
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.
add a note
User Contributed Notes
Seguridad del sistema de archivos
anonymous
17-Nov-2005 02:58
(A) Better not to create files or folders with user-supplied names. If you do not validate enough, you can have trouble. Instead create files and folders with randomly generated names like fg3754jk3h and store the username and this file or folder name in a table named, say, user_objects. This will ensure that whatever the user may type, the command going to the shell will contain values from a specific set only and no mischief can be done.
(B) The same applies to commands executed based on an operation that the user chooses. Better not to allow any part of the user's input to go to the command that you will execute. Instead, keep a fixed set of commands and based on what the user has input, and run those only.
For example,
(A) Keep a table named, say, user_objects with values like:
username|chosen_name |actual_name|file_or_dir
--------|--------------|-----------|-----------
jdoe |trekphotos |m5fg767h67 |D
jdoe |notes.txt |nm4b6jh756 |F
tim1997 |_imp_ folder |45jkh64j56 |D
and always use the actual_name in the filesystem operations rather than the user supplied names.
(B)
<?php
$op = $_POST['op'];$dir = $_POST['dirname'];switch($op){
case "cd":
chdir($dir);
break;
case "rd":
rmdir($dir);
break;
.....
default:
mail("webmaster@example.com", "Mischief", $_SERVER['REMOTE_ADDR']." is probably attempting an attack.");
}
fmrose at ncsu dot edu
09-Oct-2005 04:31
All of the fixes here assume that it is necessary to allow the user to enter system sensitive information to begin with. The proper way to handle this would be to provide something like a numbered list of files to perform an unlink action on and then the chooses the matching number. There is no way for the user to specify a clever attack circumventing whatever pattern matching filename exclusion syntax that you may have.
Anytime you have a security issue, the proper behaviour is to deny all then allow specific instances, not allow all and restrict. For the simple reason that you may not think of every possible restriction.
joshudson';DROP TABLE EMAILS;' gmail.com
01-Sep-2005 09:50
I keep application configuration files in the document root. I found the most effective trick to prevent access to them is to
1. Give them no code that actually runs when included (except for variable assignments),
2. Don't use register globals so nobody can do anything weird,
3. Name them *.php so PHP runs them when asked for
4. Don't have anything before <?php
5. Don't have a ?>
1 at 234 dot cx
23-Jun-2005 05:24
I don't think the filename validation solution from Jones at partykel is complete. It certainly helps, but it doesn't address the case where the user is able to create a symlink pointing from his home directory to the root. He might then ask to unlink "foo/etc/passwd" which would be in his home directory, except that foo is a symlink pointing to /.
Personally I wouldn't feel confident that any solution to this problem would keep my system secure. Running PHP as root (or some equivalent which can unlink files in all users' home directories) is asking for trouble.
If you have a multi-user system and you are afraid that users may install scripts like this, try security-enhanced Linux. It won't give total protection, but it at least makes sure that an insecure user script can only affect files which the web server is meant to have access to. Whatever script someone installs, outsiders are not going to be able to read your password file---or remove it.
Jones at partykel dot de
10-Dec-2004 02:00
What about:
<?php
$file_to_delete = '/home/'.$username.'/'.$userfile;
if ((!ereg('\.\.', $file_to_delete)) and (file_exists($file_to_delete))) {
unlink($file_to_delete);
}
?>
I think this should prevent every attempt to go outside the user-directory.
Additionally you should check usernames at the registration.
Another way whould be to use the user-ID as home-directory - so, this can't be changed and every registered user as an unique one (if it's a primary key in your database). But then you still have to check the given $userfile.
So the code above could be taken as a "last instance check" directly before finally deleting of the file.
akul at inbox dot ru
06-May-2004 09:59
Common and simple way to avoid path attack is separating objectname and filesystem space when possible. For example if I have users on my site and directory per user solution is not "httpdocs/users/$login", but "httpdocs/users/".md5($login) or "httpdocs/users/".$userId
tim at correctclick dot com
30-Mar-2002 04:48
One more thing --
whenever you connect to a database with a password hard coded into your script, make sure you put the script off of your web document tree. Put the script somewhere where apache won't serve documents, and then include/require this file in your other scripts. That way, if the server ever gets misconfigured, it won't serve your PHP scripts with passwords, etc. as plain text for all to see.
-Tim
cronos586(AT)caramail(DOT)com
05-Jan-2002 03:48
when using Apache you might consider a apache_lookup_uri on the path, to discover the real path, regardless of any directory trickery.
then, look at the prefix, and compare with a list of allowed prefixes.
for example, my source.php for my website includes:
if(isset($doc)) {
$apacheres = apache_lookup_uri($doc);
$really = realpath($apacheres->filename);
if(substr($really, 0, strlen($DOCUMENT_ROOT)) == $DOCUMENT_ROOT) {
if(is_file($really)) {
show_source($really);
}
}
}
hope this helps
regards,
KAT44
devik at cdi dot cz
21-Aug-2001 07:52
Well, the fact that all users run under the same UID is a big problem. Userspace security hacks (ala safe_mode) should not be substitution for proper kernel level security checks/accounting.
Good news: Apache 2 allows you to assign UIDs for different vhosts.
devik
eLuddite at not dot a dot real dot addressnsky dot ru
11-Nov-2000 09:44
I think the lesson is clear:
(1) Forbit path separators in usernames.
(2) map username to a physical home directory - /home/username is fine
(3) read the home directory
(4) present only results of (3) as an option for deletion.
I have discovered a marvelous method of doing the above in php but this submission box is too small to contain it.
:-)
| |
|
| Chiste de... Niños | | Fuerza mayor | El maestro le pregunta a Juanito:
- ¿Por qué no viniste ayer?
- Es que se murió mi abuelo.
- Está bien, pero que no se vuelva a repetir. | | Chistes en tu mail | | ©ContenidosGratis |
| Inicio | Acción | Estrategia | Palabras | Puzzles | Solitarios | Foro Trucos |  | Cake Mania Jugadores: 6835 Categoría del juego: Acción Objetivo del juego: Ayuda a Jill a recuperar la pastelería de su abuela llevando su propia pastelería; consigue clientes y gana dinero. |
|  | Rainbow Web Jugadores: 2199 Categoría del juego: Puzzles Objetivo del juego: Rompe un pegajoso hechizo y salva un reino de fantasía en Rainbow Web. Tendrás toneladas de diversión mientras juegas a este mágico desafío para la mente. |
|  | Mahjongg Fortuna Jugadores: 12462 Categoría del juego: Solitarios Objetivo del juego: Velocidad y habilidad mental son las armas más importantes en esta versión de un antiguo juego asiático. Despeja el tablero lo antes posible haciendo clic en las fichas iguales y gánate la fama eterna de la puntuación más alta. |
|  | Chainz 2 Jugadores: 6955 Categoría del juego: Puzzles Objetivo del juego: Entra en el mundo de las combinaciones con Chainz 2: Relinked, emocionante secuela del exitazo del año pasado, Chainz. Gira eslabones y crea combinaciones de 3 ó más. |
|  | Delicious Jugadores: 4405 Categoría del juego: Acción Objetivo del juego: ¿Eres un as de la multitarea? ¿Quieres que tus clientes estén contentos? ¡Pues Delicious es tu juego! Sacia el apetito de los clientes y tenlos contentos; ¡no te arriesgues! |
|  | Bookworm Jugadores: 4568 Categoría del juego: Palabras Objetivo del juego: Junta las letras para formar palabras. ¡Las palabras más largas valen más puntos! |
|  | Zuma Jugadores: 4976 Categoría del juego: Acción Objetivo del juego: Controla el ídolo de la rana de piedra de los antiguos Zuma en este intrigante enigma de acción. ¡Dispara bolas para formar conjuntos de tres, pero si dejas que lleguen a la calavera dorada morirás! |
|  | Jewel of Atlantis Jugadores: 3798 Categoría del juego: Puzzles Objetivo del juego: Descubre la ciudad hundida de la Atlántida y busca valiosos tesoros. Viaja más allá de las profundidades del mar y vive trepidantes aventuras en Jewel of Atlantis. |
|  | Jewel Quest Jugadores: 3727 Categoría del juego: Puzzles Objetivo del juego: Convierte la arena de la antigua selva en oro tan rápido como puedas juntando grupos de 3 elementos. ¡Los grupos más grandes valen más puntos! |
|  | Bejeweled 2 Jugadores: 3659 Categoría del juego: Puzzles Objetivo del juego: Con cuatro modos de juego únicos y fascinantes, nuevas piezas de juego explosivas e imponentes fondos planetarios, Bejeweled 2 es mucho más adictivo que nunca. |
|
|