Moin!
Moin again,
Woher weiß show.php die Variable $secret? Ist die fest definiert? Dann hast du verloren!
Nur wenn sie pro Request bzw. pro Session neu definiert und als Session-Variable _nicht_ an den Browser übergeben wird, sondern auf dem Server verbleibt, bringt sie etwas.
Hmm... wenn $secret fest definiert ist, und ich per MD5 einen String verschlüssele, der aus $secret . $dateiname . $sessionid zusammengesetzt ist, dann hast Du doch keine Möglichkeit, das nachzuvollziehen, oder habe ich da einen Denkfehler? Die Variable Größe ist die SessionID, die könntest Du zur not nachvollziehen, $secret aber nicht. Auch wenn sie immer gleich ist. Du kennst Sie ja nicht und sie ist verschlüsselt zusammen mit der SessionID.
Der MD5-Hash nützt dir ja nichts, wenn du ihn nicht in show.php mit den dort hineingepflanzten Werten vergleichst.
Das bedeutet: Um die URL zu generieren, benutzt du $secret, $dateiname und $sessionid.
In der URL enthalten sind schon: $sessionid und $dateiname. Fehlt noch $secret. Da dieser Wert aber konstant ist, brauch ich ihn gar nicht kennen. Ich muß nur die zum MD5-Hash passenden Werte für $sessionid und $dateiname wählen, und komme dann an das Bild. Und zufällig kenne ich eine Kombination aus $dateiname, $sessionid und MD5-Hash, die mir ein Bild liefert: Nämlich genau die URL, die du in die Seite geschrieben hast, um das Bild zu liefern.
Mit anderen Worten: Die Session hilft dir absolut gar nicht, der MD5-Hash hilft dir auch nicht. Wenn du prüfen willst, ob der Hash gültig ist, verläßt du dich auf die Konstante $secret, und den übermittelten Dateinamen $dateiname sowie auf die Session-ID, die man ebenfalls festlegen kann, sofern man sie kennt.
Oder als Gleichungen ausgeführt:
$md5 = md5(SECRET + $dateiname + $sessionid)
URL = $md5 + $dateiname + $sessionid
Das generiert die URL.
Und um zu prüfen, ob die URL geht, verwendest du nur URL-Daten.
$md5 == md5(SECRET + URL($dateiname) + URL($sessionid))
Oder auch:
md5(SECRET + $dateiname + $sessionid) == md5(SECRET + URL($dateiname) + URL($sessionid))
Da SECRET == SECRET und $dateiname == URL($dateiname) und $sessionid == URL($sessionid), wird auch jegliche MD5-Prüfsumme von beiden Seiten immer identisch sein.
show.php kriegt alle Informationen, die es prüft, per URL vom Client. Und da du die URLs natürlich dynamisch generierst und nur gültige URLs erzeugst, erlaubt allein die URL Zugriff - wenn in der URL ein Bestandteil versteckt wird, der einem beliebigen Client nicht bekannt ist, so wie z.B. ein dynamischer Anteil $secret, der sich pro Request oder zumindest pro Session verändert, und auch nicht von der Session-ID abhängt (die kann man zur Not aus dem Cookie auslesen und in die URL packen), sondern zufällig generiert wird und als Session-Variable den Server niemals verläßt - erst dann funkioniert dein Schutz.
Der verändert sich doch pro Bild und Session, da mein Hash aus $secret, $dateiname und $sessionid zusammengesetzt wird.
Ja, da ändert sich was. Aber niemand wird gehindert, die Session-ID selbst vorzugeben. Und wenn _ein_ Bild geladen werden soll, dessen Existenz bekannt ist, und dessen eine URL bekannt ist, kann diese URL immer wieder dazu verwendet werden, das Bild zu laden (es sei denn, es ist ein Authentifizierungsmechanismus davor).
$sessionid kann auf den Wert gesetzt werden, den die Session zur Auslieferung der URL mal hatte, $secret ist konstant (und für die Sicherheit irrelevant), und $dateiname ist genau das Bild, was man gerne hätte.
Deine Vorgehensweise verhindert mehr oder weniger, dass man durch Ausprobieren _andere_ Bilder erhält, deren URL man noch nicht kennt. Allerdings kann man solch einen Effekt auch erreichen, indem man einfach nur einen sessionbasierten Authentifizierungsmechanismus vor die Bildauslieferung setzt:
show.php?dateiname=bild.gif&PHPSESSID=sessionid
Solch ein Link reicht vollkommen aus. Da steht eindeutig der Bildname drin, und die Session-ID, unter der der Benutzer angemeldet ist. Die show.php erkennt anhand der ID den angemeldeten Benutzer, kennt daraufhin auch die Zugriffsrechte des Benutzers, und kann den Zugriff auf das gewünschte Bild gestatten oder verweigern. Und damit der rumspielende User nicht Hinweise darauf kriegt, welche Bilder es tatsächlich gibt, die er aber nicht sehen darf, sollte das Skript bei verweigertem Zugriff mit einem Status "404 Not found" antworten, ebenso wie bei wirklich nicht gefundenen Bildern.
Wie gesagt: Diese Methode greift echt auf Session-Informationen zurück, die der Client _nicht_ besitzt. Man kann nicht einfach eine Session-ID erfinden (bzw. eine altbekannte ID benutzen), um jederzeit Zugriff auf das Bild zu erhalten, weil bei erfundenen IDs keine Session-Variablen auf dem Server vorhanden sind, die den Benutzer authentifizieren, und bei alten Session-IDs meldet sich der Benutzer irgendwann ab bzw. erfolgt ein Timeout, so dass die Authentifizierungsdaten irgendwann verfallen und einen Zugriff ebenfalls unmöglich machen.
Und man kann aufgrund der Menge an Session-IDs, die es gibt, auch unmöglich eine aktive Session-ID raten. Das dauert Jahrtausende und würde einen derzeit von einem Server absolut noch nicht zu bewältigenden Datenstrom erfordern.
- Sven Rautenberg