Im Hinblick auf dieses Video: (Link) Möchte ich hier eine Methode vorstellen, mit der Bilder auf der eigenen Webseite vor dem direkten Zugriff via “Bild anzeigen” geschützt werden können:
Das Grundlegende Prinzip
Im folgenden soll mit dieser Ordnerstruktur gearbeitet werden:
-root/
—— images/
—— hidden/
Wir wollen dem Benutzer vorgaukeln, unsere Bilder lägen im Ordner images. In Wahrheit liegt dort aber nur eine php-Datei, welche Prüft, ob auf sie direkt oder indirekt zugegriffen wird. Wird indirekt auf sie zugegriffen, zeigt sie das gewünschte Bild. Wird hingegen direkt auf sie zugegriffen, soll sie kein Bild zeigen.
Bilder Schützen
Die eigentlichen Bilder werden grundsätzlich alle in ein Verzeichnis (hier: hidden, ein weniger einfacher Name wäre eventuell sinnvoll) hochgeladen, auf welches von außen zugegriffen werden darf. Das lässt sich mit einer einfachen .htaccess in ebendiesem Ordner festlegen:
order deny,allow
deny from all
Bilder aufrufen
Nun sind also alle Bilder vor dem Zugriff von außen geschützt, das ist ja auch unser Ziel. Es gibt jedoch ein Problem: Das Einbinden in eine Webseite stellt ja auch einen Zugriff von außen dar. Also müssen wir noch auf irgend eine Weise erkennen können, ob der Zugriff auf das Bild nun über die Webseite oder direkt erfolgt ist. Hierfür schlage ich später zwei Varianten vor. Zunächst bauen wir uns jedoch ein grobes Grundgerüst für unsere “Bildanzeigedatei”:
Zunächst legen wir im Ordner “images” eine Datei namens show.php an. Diese wird später via get-Parameter eine URL entgegennehmen und das Bild, welches unter dieser URL verfügbar ist, anzeigen.
Der Bildaufruf soll später auf folgende Weise erfolgen können:
<img src="images/meinUnterordner/nochEinUnterordner/meinBild.jpg" />
Wer genau aufgepasst hat, wird gemerkt haben: das kann so noch überhaupt nicht funktionieren. Warum? Wir wollen unsere Bilder ja gar nicht in den Ordner images hochladen, sondern in den Ordner hidden. Wird ein Bild also auf der Seite auf diese Weise aufgerufen, wird es nicht angezeigt werden können, weil es unter diesem Pfad nicht existiert. Im Ordner images liegt im Moment nur unsere show.php ohne Inhalt und das ist auch gut so.
Was brauchen wir also?
1. Eine Weiterleitung via htaccess
Damit unsere Anfragen nach images/meinUnterordner/nochEinUnterordner/meinBild.jpg oder ähnlichem später auch tatsächlich bei unserem Anzeigescript landen, müssen wir dafür sorgen, dass der Server die Anfrage für uns auf das Anzeigescript umbiegt. Und das geht folgendermaßen:
Wir legen im Ordner Images eine htaccess-Datei mit folgendem Inhalt an:
RewriteEngine on
RewriteRule ^([^\.]+)\.(png|jpg|gif)$ show.php?file=$1&type=$2 [NC,L]
Diese Zeilen sorgen dafür, dass der Server beim Aufruf eines Bildes nicht an der eigentlich in der URL angegebenen Stelle sucht, sondern unser php-Script aufruft. Als Parameter mit dem Namen “file” wird dem Script dabei die URL unseres Bildes mitgegeben. Das können wir jetzt in der PHP-Datei nutzen und zeigen mit Hilfe dieses Parameters das korrekte Bild an:
Bilder mittels php aufrufen und anzeigen
<?php
error_reporting(E_ALL);
//Korrekten Header setzen
switch($_GET["type"]){
case "gif":
header('Content-type: image/gif');
break;
case "jpg":
header('Content-type: image/jpg');
break;
case "png":
header('Content-type: image/png');
break;
}
//Bild einlesen und ausgeben
print(file_get_contents("../hidden/".$_GET["file"].".".$_GET["type"]));
?>
Dieses Script sucht an der angegebenen Stelle nach dem Bild, nur weiß dieses Script im Gegensatz zum Webseitenbenutzer, dass es im Ordner “hidden” nachsehen muss. Dort findet es dann also die Datei, ließt sie ein und gibt sie via print an den Browser des Benutzers aus. Durch den vorher gesetzten Header weiß dieser, dass es sich um ein Bild und nicht um Text handelt und zeigt dieses entsprechend an.
Und wo bleibt der Schutz jetzt?
Dieser ist wenn die obige Vorarbeit geleistet wurde sehr einfach zu implementieren. Es muss dafür lediglich die php-Datei ein wenig angepasst werden. Achtung: Dieser „Schutz“ ist so auf keinen Fall zum wirklichen Einsatz gedacht, sondern soll nur das Prinzip verdeutlichen.
Das Prinzip hinter dieser Schutzmethode ist, dass bei jedem Seitenaufruf pro Bild ein einmaliges Passwort generiert wird, welches nur für einen einzigen Aufruf gültig ist. Das Bild kann mit diesem Passwort in die Seite eingebunden werden und wird dort auch korrekt angezeigt. Versucht man jedoch, das Bild ohne Passwort oder mit dem selben Passwort ein zweites mal einzubinden, wird dieser Versuch geblockt.
Zunächst legen wir im Ordner “images” einen neuen Ordner namens “key” an und Schützen ihn mit der gleichen htaccess wie den “hidden”-Ordner. Was der Sinn dahinter ist, wird gleich erklärt.
Für alle Aufgaben, welche mit dem Passwort zu tun haben, legen wir uns zunächst eine neue php-Datei mit dem Namen pwgen.php in den Ordner images. Diese bekommt den folgenden Inhalt:
<?php
function checkpw($pass){
if(file_exists("key/".$pass)){
unlink("key/".$pass);
return true;
} else {
return false;
}
}
function generatepw($num = 1){
$pws = "";
for($i=1; $i <= $num; $i++){
$pws[$i-1] = randomstring();
fopen("images/key/".$pws[$i-1] , "w");
}
return $pws;
}
function randomstring($length = 16) {
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
$pass = "";
$i = 0;
while ($i < $length) {
$num = rand() % strlen($chars);
$tmp = substr($chars, $num, 1);
$pass = $pass . $tmp;
$i++;
}
return $pass;
}
?>
Wir haben jetzt also zwei wichtige Funktionen: zunächst generatepw: diese Funktion generiert eine angegebene Zahl von zufälligen Strings und legt im Ordner “key” für jeden String eine Datei an. Dann gibt sie die Keys zurück, damit diese beim Bildaufruf genutzt werden können.
Als zweite wichtige Funktion ist checkpw enthalten: Sie prüft, ob im Ordner “key” eine Datei mit dem angegebenen Key enthalten ist. Wenn ja, löscht sie diese und gibt true zurück. Das löschen dieser Datei garantiert, dass jeder Key nur genau einmal genutzt werden kann.
Die letzte Funktion generiert zufällige Strings von einer bestimmten Länge und stammt nicht von mir, sondern wurde von hier (noobis.de) kopiert und leicht abgewandelt.
Damit wäre eigentlich auch ein Großteil geschafft. Jetzt muss nurnoch der untere Teil der show.php angepasst werden:
$parts = explode("-", $_GET["file"], 2);
if(checkpw($parts[0]) == true){
print(file_get_contents("../hidden/".$parts[1].".".$_GET["type"]));
} else{
print(file_get_contents("error.jpg"));
}
und natürlich müssen zum aufrufen der Bilder die Passwörter angefordert und in die Einbindung integriert werden:
<?php
include("images/pwgen.php");
//Passwörter anfordern
$pws = generatepw(2);
?>
<img src="images/<?php echo $pws[0]."-"; ?>testordner/bild1.jpg" />
<img src="images/<?php echo $pws[1]."-"; ?>testordner/bild2.png" />
Natürlich kann eine beliebige Anzahl an Passwörtern angefordert und genutzt werden.
Um diese Methode wirklich produktiv einzusetzen, empfiehlt es sich, eine Datenbank zu nutzen, anstatt für jeden Key eine Datei anzulegen. Das hätte jedoch den Code größer und unübersichtlicher gemacht (und außerdem bietet nicht jeder Server eine Datenbank an), weshalb ich darauf verzichtet habe. Außerdem ist es mit diesem Code relativ aufwändig, Bilder einzubinden, da immer von Hand der jeweilige Schlüssel im href des img-Tags eingetragen werden muss (Das <?php echo $pws[*]."-"; ?>
) . Auch an dieser Stelle gibt es bestimmt noch verbesserungsbedarf. Ich denke jedoch, das grundlegende Prinzip wird auch mit diesem Code klar.