Tom: Uploads planen und überwachen

Beitrag lesen

Hello,

habe bereits einen funktionierenden Upload in PHP.

aus dem weiteren Thread habe ich entnommen, dass Du eventuell gar nicht weißt, warum das Upload-Script funktioniert. Dann könnte es auch sein, dass Du gar nicht weißt, welche garviernden Sicherheitslücken es haben könnte oder sogar hat.

Deshalb nochmals ein paar Regeln zum Upload:
--------------------------------------------

Der User kann alles auf den Server hochladen, was ihm gefällt. Die einzigen Einschränkungen dabei sind:

  • der Server muss einen Upload überhaupt annehmen
  • die Zeitdauer für den Upload überschreitet nicht die eingestellte
  • die Datenmenge überschreitet nicht die eingestellte

Der Client kann also auch *.EXE-Files, *.PHP-Files, ausführbare Scripte und Programme für Linux usw. hochladen. Gerade, wenn Du diese dann später direkt mit einem Link versiehst, ist die Lücke aufgerissen. man muss oft nur ein PHP-Script hochladen und es mit dem Browser aufrufen. Schon istr es passiert.

Abhilfe:

Upload überwachen
-----------------

Nach dem Upload als erstes die Variable

$_FILES[$steuerelementname]['error'] === 0

prüfen. Nur wenn die identisch 0 ist, wurde der Upload technisch einwandfrei mit _einem_ File durchgeführt.
Sie kann aber auch ein Array sein, dann muss eben

$_FILES[$steuerelementname]['error'][0] === 0
  $_FILES[$steuerelementname]['error'][1] === 0
  $_FILES[$steuerelementname]['error'][2] === 0
  ...

sein, damit alle Files technisch einwandfrei angekommen sind.

Files untersuchen
-----------------

Dann sollte man als nächstes auf dem Server prüfen, welchen Typ die Dateien haben.
Dazu darf man _N_I_C_H_T_ der Angabe in

$_FILES[$steuerelementname]['type']          ## ist nicht vertrauenswürdig !

trauen. Sie ist vom Client eingetragen worden und daher nicht vertrauenswürdig.

Wenn man z.B. nur Bilder zulassen will, hilft

getimagesize()

http://www.php.net/manual/en/function.getimagesize.php

Wenn man nur Textdateien[1] zulassen will, aber ausführbare Programme, Bilder, etc verhindern will,
hilft eine Untersuchung der Datei auf

if(strpos($dateiinhalt,chr(0)) !== false     ## Diese Datei ist keine reguläre Textdatei

Meistens reichen schon die ersten 256 Bytes einer Datei, um eine 0 (binär 00000000) zu finden.
Wenn also eine 0 enthalten ist, kann die Datei keine reguläre Textdatei sein!
Das gilt aber keinesfalls sicher anders herum.

Dann gibt es noch die Funktion

mime_content_type() [http://www.php.net/manual/en/function.mime-content-type.php]

die aber nicht in allen PHP-Versionen vorhanden war und auch inzwischen abgekündigt wurde.
Ohne die PECL extension und Fileinfo

http://www.php.net/manual/en/ref.fileinfo.php

wird man also nicht auskommen, wenn man etwas anderes als Bilder zulassen will.

Namen frei vergeben
-------------------

Eine weitere Möglichkeit für "Injections" ist der Name des hochgeladenen Files.
In

$_FILES[$steuerelementname]['name']

steht i.d.R. der vom Client mitgeteilte Name des Files. Er kann aber auch leer sein oder aber,
was viel schlimmer ist, einen ganzen Pfad enthalten. Deshalb darf man ihn

NIE NICHT NIMMER direkt verwenden!

Vertrauenswürdig ist hingegen der Name $_FILES[$steuerelementname]['tmp_name'], da dieser
vom Server generiert wird. Aber auch jeder andere Name, den man sich erzeugt, ist besser
als der vom Client übermittelte.

Wenn man sich aber trotzdem merken will, was der Client als Dateinamen vorgeschlagen hat,
sollte man ihn mittels

$_merkname = basename($_FILES[$steuerelementname]['name']);

auf seinen Namensanteil reduzieren lassen. Was interessiert uns auch der Pfad auf dem Client?
Bei der Erfindung eines Namens für das permanent gespeicherte File muss man natürlich darauf
achten, dass dieser nicht schon vorhanden ist im Ablageverzeichnis.
Auch dies ist ein Grund dafür, dass man den vom Client gemeldeten Namen meistens nicht
verwenden kann, denn wenn mehrere User Files ins selbe Verzeichnis hochladen können, wissen
die i.d.R. ja nicht, welche Namen die anderen schon benutzt haben.

Verzeichnis "kastrieren"
------------------------

Bei üblichen PHP-Einrichtungen bei Hostern werden Script-Dateien (zumindest PHP) in allen
verfügbaren Verzeichnissen unter der DOCUMENT_ROOT auch durch den zugehörigen Parser geschickt;
eine passende Endung ist meistens die einzige Voraussetzung dafür.

In Verzeichnissen, in denen Bilder gespeichert werden sollen oder Textdateien, die vom Client
über HTTP abgefordert werden können (HTML ist auch Text), sollte man daher keine PHP-Dateien
speichern und zulassen. Dem Server sollte man mitteilen, dass Dateien in diesem Verzeichnis
NICHT geparst werden dürfen. Das kann man oft mittels einer ".htaccess-Datei" tun

<FilesMatch ".(php|phtml|html)$">

forceType text/html

</FilesMatch>

Das ist bitte nur als Beipiel zu sehen, wo es langgehen kann.
Wahrscheinlich ist es besser, man baut die Bedingungen und die regulären Ausdrücke so auf,
dass nur "die guten Files" überhaupt entsprechend ihrer Bestimmung ausgeliefert werden und
alle anderen zur Auslieferung einer Fehlerseite führen.

Jedenfalls zeigen diese Anregungen hoffentlich, dass man nicht aufhören darf, wenn es

"so eben funzt"

sondern sich weitaus mehr Gedanken machen muss. AUCH ALS PROVIDER!

http://www.php.net/manual/en/features.file-upload.php
http://httpd.apache.org/docs/2.0/mod/directives.html

Über eine Ergänzung des Threads würde ich mich freuen.

Harzliche Grüße vom Berg
http://www.annerschbarrich.de

Tom

--
Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
Nur selber lernen macht schlau