-
Notifications
You must be signed in to change notification settings - Fork 44
/
Copy pathfilesystem.xml
247 lines (219 loc) · 7.96 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
235
236
237
238
239
240
241
242
243
244
245
246
247
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- EN-Revision: 91570644fbbe4d23e79908e1a04c4c4d003fe587 Maintainer: hholzgra Status: ready -->
<!-- Credits: tom -->
<chapter xml:id="security.filesystem" xmlns="http://docbook.org/ns/docbook">
<title>Sicherheit des Dateisystems</title>
<simpara>
<acronym>PHP</acronym> ist hinsichtlich der Berechtigungen auf Datei-
und Verzeichnisebene von den in den meisten Serversystemen implementierten
Sicherheitseinstellungen abhängig. Dies verleiht Ihnen Kontrolle darüber,
welche Dateien im Dateisystem gelesen werden dürfen. Es sollte
sichergestellt werden, dass alle öffentlich zugänglichen Dateien von allen
Benutzern, die Zugang zu diesem Dateisystem haben, gelesen werden können,
ohne die Sicherheit zu gefährden.
</simpara>
<simpara>
Da <acronym>PHP</acronym> entwickelt wurde, um Zugriffe auf das Dateisystem
auf Benutzebene zu erlauben, ist es natürlich auch möglich, ein
<acronym>PHP</acronym>-Skript zu schreiben, dass Ihnen erlaubt,
Systemdateien wie <filename>/etc/passwd</filename> zu lesen,
Ethernetverbindungen zu modifizieren, enorme Druckaufträge zu senden
etc. Dies hat offensichtliche Implikationen, indem Sie sicherstellen
müssen, dass alle von Ihnen zu lesenden bzw. zu schreibenden Dateien
auch die richtigen sind.
</simpara>
<simpara>
Stellen Sie sich folgendes Skript vor, in dem ein Benutzer zum Ausdruck
bringt, dass er eine Datei in seinem Heimatverzeichnis löschen möchte.
Es wird davon ausgegangen, dass ein <acronym>PHP</acronym>-Webinterface
regelmäßig für das Dateimanagement verwendet wird und dass der
Apache-Benutzer berechtigt ist, in seinem Heimatverzeichnis Dateien zu
löschen.
</simpara>
<para>
<example>
<title>Schlechte Variablenprüfung führt zu....</title>
<programlisting role="php">
<![CDATA[
<?php
// Löschen einer Datei aus dem Heimatverzeichnis des Users
$username = $_POST['user_submitted_name'];
$userfile = $_POST['user_submitted_filename'];
$homedir = "/home/$username";
unlink("$homedir/$userfile");
echo "Die Datei wurde gelöscht!";
?>
]]>
</programlisting>
</example>
Da Benutzer- und Dateiname über ein Benutzerformular bereitgestellt werden,
kann jeder jemand anderes Benutzer- und Dateinamen übertragen und so
Dateien löschen, ohne über die entsprechnde Erlaubnis zu verfügen.
In diesem Fall empfiehlt es sich, eine andere Form der Authentifizierung zu
verwenden. Stellen Sie sich vor was passieren würde, wenn die übertragenen
Variablen <literal>"../etc/"</literal> und <literal>"passwd"</literal>
beinhalten würden.
Der Code würde dann folgendermaßen aussehen:
<example>
<title>... Ein Angriff auf das Dateisystem</title>
<programlisting role="php">
<![CDATA[
<?php
// Löscht eine Datei irgendwo auf der Festplatte, wo der Benutzer
// die nötigen Rechte besitzt. Wenn PHP root-Zugriff hat:
$username = $_POST['user_submitted_name']; // "../etc"
$userfile = $_POST['user_submitted_filename']; // "passwd"
$homedir = "/home/$username"; // "/home/../etc"
unlink("$homedir/$userfile"); // "/home/../etc/passwd"
echo "Die Datei wurde gelöscht!";?>
?>
]]>
</programlisting>
</example>
Es gibt zwei wichtige Kriterien die Sie beachten sollten, um diese
Dinge zu vermeiden:
<itemizedlist>
<listitem>
<simpara>
Erteilen Sie dem <acronym>PHP</acronym> Web-user (Binärdatei) nur eingeschränkte Rechte.
</simpara>
</listitem>
<listitem>
<simpara>
Prüfen Sie alle übertragenen Variablen.
</simpara>
</listitem>
</itemizedlist>
Hier ist ein verbessertes Skript:
<example>
<title>Etwas sicherere Prüfung des Dateinamens</title>
<programlisting role="php">
<![CDATA[
<?php
// Löscht eine Datei von der Festplatte, auf die
// der PHP-Benutzer Zugriff hat.
$username = $_SERVER['REMOTE_USER']; // using an authentication mechanism
$userfile = basename($_POST['user_submitted_filename']);
$homedir = "/home/$username";
$filepath = "$homedir/$userfile";
if (file_exists($filepath) && unlink($filepath)) {
$logstring = "$filepath gelöscht\n";
} else {
$logstring = "$filepath konnte nicht gelöscht\n";
}
$fp = fopen("/home/logging/filedelete.log", "a");
fwrite($fp, $logstring);
fclose($fp);
echo htmlentities($logstring, ENT_QUOTES);
?>
]]>
</programlisting>
</example>
Auch dies nicht ohne Schwachstellen. Wenn Ihr Authentifizierungssystem
Benutzern erlauben sollte, deren eigene Logins zu kreieren, und ein
Benutzer wählt den Login <literal>"../etc/"</literal>, ist das System
erneut angreifbar. Aus diesem Grund sollten Sie eventuell eine speziellere
Überprüfung durchführen
<example>
<title>Sicherere Dateinamensprüfung</title>
<programlisting role="php">
<![CDATA[
<?php
$username = $_SERVER['REMOTE_USER']; // Nutzung eines Authentifikationsmechanismus
$userfile = $_POST['user_submitted_filename'];
$homedir = "/home/$username";
$filepath = "$homedir/$userfile";
if (!ctype_alnum($username) || !preg_match('/^(?:[a-z0-9_-]|\.(?!\.))+$/iD', $userfile)) {
die("Ungültiger Benutzer- oder Dateiname");
}
// etc.
?>
]]>
</programlisting>
</example>
</para>
<para>
Abhängig vom Betriebssystem gibt es eine große Anzahl Dateien, auf die Sie
achten sollten, inklusive Einträge für Geräte (<filename>/dev/</filename>
oder <filename>com1</filename>), Konfigurationsdateien (die Dateien in
<filename>/etc/</filename> und die <literal>.ini</literal>-Dateien),
allgemein bekannte Verzeichnisse (<filename>/home/</filename>,
<filename>My Documents</filename>) etc. Aus diesem Grund ist es für
gewöhnlich einfacher, eine Richtlinie zu erstellen, in der alles verboten
ist, was Sie nicht ausdrücklich erlauben.
</para>
<sect1 xml:id="security.filesystem.nullbytes">
<title>Probleme im Zusammenhang mit Nullbytes</title>
<simpara>
Da <acronym>PHP</acronym> die Funktionen der C-Standardbibliothek für
Dateisystemoperationen nutzt kann es Nullbytes in unerwarteter Weise
verarbeiten.
Da Nullbytes in C das Stringende festlegen werden Strings die solche
enthalten nicht vollständig verarbeitet sondern nur bis zum ersten
Auftreten eines Nullbytes.
Das folgende Beispiel zeigt einen anfälligen Code, der dieses Problem
verdeutlicht:
</simpara>
<example>
<title>Skript mit Nullbyte-Verwundbarkeit</title>
<programlisting role="php">
<![CDATA[
<?php
$file = $_GET['file']; // "../../etc/passwd\0"
if (file_exists('/home/wwwrun/' . $file . '.php')) {
// file_exists gibt true zurück, da /home/wwwrun/../../etc/passwd existiert
include '/home/wwwrun/' . $file . '.php';
// Die Datei /etc/passwd wird eingebunden
}
?>
]]>
</programlisting>
</example>
<para>
Daher sollte jede nicht vertrauenswürdige Zeichenkette, die in
Dateisystemoperationen verwendet wird, ordentlich geprüft werden.
Hier sehen Sie eine eine bessere Version des vorhergehenden Beispiels:
</para>
<example>
<title>Korrekte Validierung der Eingabe</title>
<programlisting role="php">
<![CDATA[
<?php
$file = $_GET['file'];
// Liste zulässiger Werte (Whitelisting)
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
-->