-
Notifications
You must be signed in to change notification settings - Fork 58
/
Copy pathfilesystem.xml
234 lines (207 loc) · 7.95 KB
/
filesystem.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- EN-Revision: 91570644fbbe4d23e79908e1a04c4c4d003fe587 Maintainer: PhilDaiguille Status: ready -->
<!-- Reviewed: yes Maintainer: Marqitos -->
<!-- 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 <filename>/etc/passwd</filename>, 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
<literal>"../etc/"</literal> y <literal>"passwd"</literal>. 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 <literal>"../etc/"</literal>, 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 (<filename>/dev/</filename>
o <filename>COM1</filename>), archivos de configuracion (archivos <filename>/etc/</filename> y archivos <literal>.ini</literal>),
las muy conocidas carpetas de almacenamiento (<filename>/home/</filename>, <filename>My Documents</filename>), 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
-->