mirror of
https://github.com/php/doc-es.git
synced 2026-03-25 16:02:13 +01:00
git-svn-id: https://svn.php.net/repository/phpdoc/es/trunk@337541 c90b9560-bf6c-de11-be94-00142212c4b1
223 lines
7.7 KiB
XML
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
|
|
-->
|