1
0
mirror of https://github.com/php/doc-es.git synced 2026-03-25 16:02:13 +01:00
Files
archived-doc-es/security/filesystem.xml
Pedro Antonio Gil Rodríguez 5e9e70cbff Actualización a la última versión
git-svn-id: https://svn.php.net/repository/phpdoc/es/trunk@337541 c90b9560-bf6c-de11-be94-00142212c4b1
2015-08-18 17:48:58 +00:00

223 lines
7.7 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- EN-Revision: ab6785b01ce1006e3a9761988575289f40c9b678 Maintainer: jvenegasperu Status: ready -->
<!-- Reviewed: no -->
<!-- splitted from ./index.xml, last change in rev 1.66 -->
<chapter xml:id="security.filesystem" xmlns="http://docbook.org/ns/docbook">
<title>Seguridad del Sistema de Archivos</title>
<simpara>
<acronym>PHP</acronym> está sujeto a la seguridad integrada en la mayoría de sistemas de servidores con
respecto a los permisos de archivos y directorios. Esto permite
controlar qué archivos en el sistema de archivos se pueden leer. Se debe
tener cuidado con los archivos que son legibles para garantizar
que son seguros para la lectura por todos los usuarios que tienen acceso al
sistema de archivos.
</simpara>
<simpara>
Desde que <acronym>PHP</acronym> fue diseñado para permitir el acceso a nivel de usuarios para el sistema de archivos,
es perfectamente posible escribir un script <acronym>PHP</acronym> que le permita
leer archivos del sistema como /etc/passwd, modificar sus conexiones de red,
enviar trabajos de impresión masiva, etc. Esto tiene algunas
implicaciones obvias, es necesario asegurarse que los archivos
que se van a leer o escribir son los apropiados.
</simpara>
<simpara>
Considere el siguiente script, donde un usuario indica que
quiere borrar un archivo en su directorio home. Esto supone una
situación en la que una interfaz web en <acronym>PHP</acronym> es usada regularmente para gestionar archivos,
por lo que es necesario que el usuario Apache pueda borrar archivos en los
directorios home de los usuarios.
</simpara>
<para>
<example>
<title>Un control pobre puede llevar a ....</title>
<programlisting role="php">
<![CDATA[
<?php
// eliminar un archivo del directorio personal del usuario
$username = $_POST['user_submitted_name'];
$userfile = $_POST['user_submitted_filename'];
$homedir = "/home/$username";
unlink("$homedir/$userfile");
echo "El archivo ha sido eliminado!";
?>
]]>
</programlisting>
</example>
Dado que el nombre de usuario y el nombre del archivo son enviados desde un formulario,
estos pueden representar un nombre de archivo y un nombre de usuario que pertenecen a otra persona,
incluso se podría borrar el archivo a pesar que se supone que no estaría permitido hacerlo.
En este caso, usted desearía usar algún otro tipo de autenticación.
Considere lo que podría suceder si las variables enviadas son
"../etc/" y "passwd". El código entonces se ejecutaría efectivamente como:
<example>
<title>... Un ataque al sistema de archivos</title>
<programlisting role="php">
<![CDATA[
<?php
// elimina un archivo desde cualquier lugar en el disco duro al que
// el usuario de PHP tiene acceso. Si PHP tiene acceso de root:
$username = $_POST['user_submitted_name']; // "../etc"
$userfile = $_POST['user_submitted_filename']; // "passwd"
$homedir = "/home/$username"; // "/home/../etc"
unlink("$homedir/$userfile"); // "/home/../etc/passwd"
echo "El archivo ha sido eliminado!";
?>
]]>
</programlisting>
</example>
Hay dos medidas importantes que usted debe tomar para prevenir estas
cuestiones.
<itemizedlist>
<listitem>
<simpara>
Únicamente permisos limitados al usuario web de <acronym>PHP</acronym>.
</simpara>
</listitem>
<listitem>
<simpara>
Revise todas las variables que se envían.
</simpara>
</listitem>
</itemizedlist>
Aquí está una versión mejorada del script:
<example>
<title>Comprobación más segura del nombre de archivo</title>
<programlisting role="php">
<![CDATA[
<?php
// elimina un archivo del disco duro al que
// el usuario de PHP tiene acceso.
$username = $_SERVER['REMOTE_USER']; // usando un mecanismo de autenticación
$userfile = basename($_POST['user_submitted_filename']);
$homedir = "/home/$username";
$filepath = "$homedir/$userfile";
if (file_exists($filepath) && unlink($filepath)) {
$logstring = "Se ha eliminado $filepath\n";
} else {
$logstring = "No se ha podido eliminar $filepath\n";
}
$fp = fopen("/home/logging/filedelete.log", "a");
fwrite($fp, $logstring);
fclose($fp);
echo htmlentities($logstring, ENT_QUOTES);
?>
]]>
</programlisting>
</example>
Sin embargo, incluso esto no está exento de defectos. Si la autenticación
del sistema permite a los usuarios crear sus propios inicios de sesión de usuario, y un usuario
eligió la entrada "../etc/", el sistema está expuesto una vez más. Por
esta razón, puede que prefiera escribir un chequeo más personalizado:
<example>
<title>Comprobación más segura del nombre de archivo</title>
<programlisting role="php">
<![CDATA[
<?php
$username = $_SERVER['REMOTE_USER']; // usando un mecanismo de autenticación
$userfile = $_POST['user_submitted_filename'];
$homedir = "/home/$username";
$filepath = "$homedir/$userfile";
if (!ctype_alnum($username) || !preg_match('/^(?:[a-z0-9_-]|\.(?!\.))+$/iD', $userfile)) {
die("nombre de usuario o nombre de archivo incorrecto");
}
//etc...
?>
]]>
</programlisting>
</example>
</para>
<para>
Dependiendo de sus sistema operativo, hay una gran variedad de archivos
a los que debe estar atento, esto incluye las entradas de dispositivos (/dev/
o COM1), archivos de configuracion (archivos /etc/ y archivos .ini),
las muy conocidas carpetas de almacenamiento (/home/, Mis documentos), etc. Por esta
razón, por lo general es más fácil crear una política en donde se prohíba
todo excepto lo que expresamente se permite.
</para>
<sect1 xml:id="security.filesystem.nullbytes">
<title>Cuestiones relacionadas a bytes nulos</title>
<simpara>
Como <acronym>PHP</acronym> utiliza las funciones de C para operaciones relacionadas al sistema de archivos,
se podría manejar bytes nulos de manera bastante inesperada.
Como un byte nulo denota el fin de una cadena en C, las cadenas que contengan estos
no serán consideradas por completo, sino sólo hasta que ocurra un byte nulo.
El siguiente ejemplo muestra un código vulnerable que presenta este problema:
</simpara>
<example>
<title>Script vulnerable a bytes nulos</title>
<programlisting role="php">
<![CDATA[
<?php
$file = $_GET['file']; // "../../etc/passwd\0"
if (file_exists('/home/wwwrun/'.$file.'.php')) {
// file_exists devolverá true si el archivo /home/wwwrun/../../etc/passwd existe
include '/home/wwwrun/'.$file.'.php';
// el archivo /etc/passwd se incluirá
}
?>
]]>
</programlisting>
</example>
<para>
Por lo tanto, cualquier cadena que se utiliza en una operación de sistema de archivos siembre deben
ser validados correctamente. He aquí una versión mejorada del ejemplo anterior:
</para>
<example>
<title>Validando correctamente la entrada</title>
<programlisting role="php">
<![CDATA[
<?php
$file = $_GET['file'];
// Lista blanca de valores posibles
switch ($file) {
case 'main':
case 'foo':
case 'bar':
include '/home/wwwrun/include/'.$file.'.php';
break;
default:
include '/home/wwwrun/include/main.php';
}
?>
]]>
</programlisting>
</example>
</sect1>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->