Sichere PHP-Web-Applikationen schreiben - Ein Überblick

Exzellenter Artikel
von Corvin Gröning | 7 | 14 Kommentare | 19151 Aufrufe

Anzeige Hier werben

Dieser Artikel soll eine Einführung in die Entwicklung von sicheren PHP-Web-Applikationen bieten. So werden einige mögliche Sicherheitslücken und ein Vorschlag zum Umgang mit diesen vorgestellt.

Am Ende der meisten Kapitel befinden sich Links zu Webseiten, die das Thema vertiefen.

register_globals

register_globals ist eine Einstellungsmöglichkeit von PHP. Wenn diese aktiviert ist, ist ein direkter Zugriff auf Variablen, die via GET- oder POST-Methode übergeben wurden, möglich.

Beispiel:

 
HTML
1
2
3
4
5
<form method="post" action="login.php" name="login">
  <input type="text" name="username" width="100" /><br />
  <input type="password" name="password" width="100" /><br />
  <input type="submit" name="login" />
</form>

Nun kann in der PHP-Datei direkt auf den Benutzernamen und das Passwort zugegriffen werden:

 
PHP
1
2
3
$userdata = array();
$userdata['name'] = $username;
$userdata['pass'] = $password;

Wenn register_globals deaktiviert ist, ist kein direkter Zugriff möglich, auf die Daten aus dem Formular kann nur über das superglobale Array $_POST zugegriffen werden:

 
PHP
1
2
3
$userdata = array();
$userdata['name'] = $_POST['username'];
$userdata['pass'] = $_POST['password'];

Das Gleiche gilt für Variablen, die mit der GET-Methode (über den URL) übergeben werden. Das zugehörige superglobale Array ist $_GET.

Der direkte Zugriff ist zwar etwas kürzer, stellt aber ein großes Sicherheitsrisiko dar.

Beispiel:

 
PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<?php
echo '<form action="" name="login" method="post">';
echo '<input type="text" name="username" width="100" />';
echo '<input type="password" name="password" width="100" />';
echo '<input type="submit" value="Login" />';
echo '</form>';

// Benutzername und Passwort überprüfen
if( $_POST['username'] == "foo" AND $_POST['password'] == "bar" ) {
    $logged_in = true;
}

// Prüfen, ob der Benutzer eingeloggt ist
if( $logged_in == true ) {
    // Die geheimen Daten ausgeben
    echo "Your secret data";
}
?>

Wenn der Benutzer den richtigen Benutzernamen und das richtige Passwort eingibt, wird "Your secret data" ausgegeben. Ein Angreifer kann dieses Login bei aktiviertem register_globals ganz einfach umgehen, indem er ?logged_in=true an den URL anhängt. Damit macht er aus diesem Code-Abschnitt:

 
PHP
1
2
3
4
5
// Prüfen, ob der Benutzer eingeloggt ist
if( $logged_in == true ) {
    // Die geheimen Daten ausgeben
    echo "Your secret data";
}

praktisch diesen:

 
PHP
1
2
3
4
5
6
$logged_in = true;
// Prüfen, ob der Benutzer eingeloggt ist
if( $logged_in == true ) {
    // Die geheimen Daten ausgeben
    echo "Your secret data";
}

Aus diesem Grund sollte register_gloabls auf jeden Fall deaktiviert werden.
Alternativ kann auch $logged_in = false; an den Anfang des Skriptes geschrieben werden (z. B. wenn der Webhoster register_globals aktiviert hat und keine Zugriff auf die php.ini erlaubt ist).

Links zum Thema:

Hinweis: Die Einstellungsmöglichkeit register_globals wird in PHP 6.0.0 entfernt. Es wird aber noch lange dauern, bis PHP 6.0.0 veröffentlicht und auf den meisten Webservern/von den meisten Webhostern eingesetzt wird. Daher wird register_globals vorerst noch ein wichtiges Thema bleiben.

XSS

XSS ist die Abkürzung für Cross Site Scripting. Es handelt sich hierbei um den Versuch, fremden Code auf einer Webseite zur Ausführung zu bringen.

Als Beispiel folgendes XSS-gefährdetes Gästebuch:

 
PHP
 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
<?php
/*---------------- 
 * Gästebuch
 *----------------
 */
$gbfile = "gb.txt";

// Was soll gemacht werden?
$action = @$_GET['action'];

switch ($action) {
    case "new":
        new_entry();
        break;
    case "write":
        write();
        break;
    case "edit":
        // ...
        break;
    case "delete":
        // ...
        break;
    default:
        display();
}

// Formular ausgeben
function new_entry() {
    echo '<form action="?action=write" name="gb" method="post">';
    echo 'Name:<br /> <input type="text" name="author" /><br />';
    echo 'Text:<br /> <textarea name="text" cols="50" rows="5"></textarea><br />';
    echo '<input type="submit" name="submit" value="Abschicken" />';
    echo '</form>';
}

// Einträge speichern
function write() {
    global $gbfile;



    $author = $_POST['author'];
    $text = $_POST['text'];

    // Speichern, wenn Text und Autor gegeben sind
    if ( !empty($author) AND !empty($text) ) {
        $file = file_get_contents($gbfile);
        $file = $author .": " .$text ."\n{}". $file;
        file_put_contents($gbfile, $file);
    }

    return true;
}

// Einträge anzeigen
function display() {
    global $gbfile;

    echo '<a href="?action=new">New Entry</a><br /><br /><br />';
    
    $file = file_get_contents($gbfile);
    $file = explode("{}", $file);
    for ( $i=0; $i<count($file)-1; $i++ ) {
        echo stripslashes( $file[$i] ) ."<hr />";
    }
    
    return true;
}
?>

Ein Angreifer könnte nun folgenden Text eingeben:
<script>document.location.href="http://domain.tld";</script>

So wäre es nicht mehr möglich, die Gästebucheinträge zu lesen, weil von der Seite zum Anzeigen der Einträge immer auf http://domain.tld weitergeleitet werden würde (wenn der Benutzer JavaScript aktiviert hat).

Um sich vor einem solchen Angriff zu schützen, kann man vor der Ausgabe der Einträge (Zeile 65) mit der Funktion htmlentities() alle HTML-Tags in Text umwandeln oder diese mit strip_tags() komplett entfernen.

Beispiel:

 
HTML
1
2
3
4
echo htmlentities( stripslashes( $file[$i] ) ) ."<hr />";

// Oder:
echo strip_tags( stripslashes( $file[$i] ) ) ."<hr />";

Bei der Verwendung von strip_tags() sollten keine Ausnahmen zugelassen werden (zweiter Parameter von strip_tags()). Denn bei

 
PHP
1
echo strip_tags( stripslashes( $file[$i] ), "<b>" ) ."<hr />";

wäre es zum Beispiel möglich Folgendes in das Gästebuch einzutragen:
<b style="font-size: 1000px; ">Hallo!!</b>

Dadurch würde der Text "Hallo!!" in einer Größe von 1000 Pixeln ausgegeben werden, wodurch das Gästebuch verschandelt werden würde.
Um dem Benutzer trotz Verwendung von htmlentities() oder strip_tags() die Möglichkeit zu geben, seinen Text zu formatieren, können entsprechende BBCodes implementiert werden.

Ein Tutorial dazu findet sich hier:

Weiterführende Links zum Thema XSS:

CSRF

CSRF steht für Cross Site Request Forgery. Ein CSRF-Angriff ähnelt einem XSS-Angriff, bei ersterem geht es aber primär darum, Objekte (wie Bilder) auf einer fremden Webseite einzubinden.
Als Beispiel das obige Gästebuch, dort ist folgender Eintrag möglich:
<img src="http://www.bad-site.com/bad-script.php" width="0" height="0" />

Es ist egal, ob das PHP-Skript zur Tarnung noch mittels den Bildfunktionen von PHP ein Bild zurückgibt oder nicht, das Skript wird ausgeführt! Dadurch, dass im <img>-Tag width und height auf 0 gesetzt wurden, wird noch nicht einmal das Symbol für eine kaputte Grafik angezeigt, der Angriff wird also vorerst nicht (oder sogar nie) bemerkt.
Ein Angreifer könnte so zum Beispiel die IP-Adressen von Benutzern mitloggen, da das Skript jedes mal ausgeführt wird, wenn jemand sich die Gästebuch-Einträge anschaut.

Eine Demonstration eines CSRF-Angriffs findet sich hier:

Weiterer Link zum Thema XSS und CSRF:

SQL-Injection

Von SQL-Injection spricht man, wenn ein Angreifer versucht, eine SQL-Abfrage zu manipulieren, um dann SQL-Befehle auszuführen, die nicht vorgesehen waren.

Dazu folgendes Beispiel:

 
PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Verbindung zu Datenbank

// Benutzername und Passwort erhalten
$username = $_POST['username'];
$password = $_POST['password'];

$sql = "SELECT 
            `id`
        FROM 
            `users`
        WHERE
            `username` = '". $username ."'
          AND
            `password` = '". $password ."'
        ";

$res = mysql_query($sql) or die ( mysql_error() );

// Prüfen, ob Benutzername und Passwort zusammenpassen
if( mysql_num_rows($res) == 1 ) {
    echo "Erfolgreich eingeloggt...";
}

Das Skript soll einen Benutzer eines Forums einloggen. Es übernimmt dazu einen Benutzernamen und ein Passwort, das in ein Formular eingegeben wurde. Anschließend wird überprüft, ob es in der Datenbank einen Eintrag gibt, bei dem sowohl der Benutzername als auch das Passwort mit den eingegebenen Daten übereinstimmt. Wenn ja, gilt der Benutzer als eingeloggt.

Ein Angreifer hätte zum Beispiel folgende Möglichkeit, die Abfrage zu manipulieren: Er gibt in das Feld für den Benutzernamen den Namen "max_m" ein (diesen könnte er zum Beispiel der Mitgliederliste des Forums entnommen haben). In das Passwort-Feld gibt er folgendes ein:
' OR username='max_m

Nach Abschicken des Formulars sieht die Abfrage dann so aus:
SELECT `id` FROM `users` WHERE `username` = 'max_m' AND `password` = '' OR username='max_m'

mysql_num_rows() liefert somit 1 zurück und der Angreifer konnte sich mit einem beliebigen Benutzernamen einloggen, ohne das zugehörige Passwort zu kennen.

Um sich vor einem SQL-Injection-Angriff zu schützen, muss man Benutzereingaben mit der Funktion mysql_real_escape_string() filtern. Dadurch werden alle Zeichen, mit Hilfe derer man eine Abfrage manipulieren könnte, "escapt". Aus ' wird zum Beispiel \'.

Vor dem Gebrauch von mysql_real_escape_string() sollte aber überprüft werden, ob die Einstellung magic_quotes_gpc aktiviert ist. Wenn ja, muss vorher die Funktion stripslashes() auf den String, der gefiltert werden soll, angewandt werden, da sonst einige Zeichen doppelt escapt werden:

 
PHP
1
2
3
4
5
6
7
if( get_magic_quotes_gpc() == 1 ) {
   $title = stripslashes( $_POST['title'] );
   $text = stripslashes( $_POST['text'] );
}

$title = mysql_real_escape_string( $_POST['title'] );
$text = mysql_real_escape_string( $_POST['text'] );

Weiterhin sollte jede SQL-Abfrage, die von einem Benutzer verfasste Daten enthält, auf Plausibilität überprüft und es sollte geprüft werden, ob der Benutzer überhaupt berechtigt ist, die Aktion durchzuführen.

Links zum Thema:

Versteckte Formularfelder

Es ist möglich, Werte an eine andere Seite über ein verstecktes Formularfeld zu übergeben. Solange der Benutzer nicht in den Quellcode schaut, sieht er nicht, was übergeben wird:

 
HTML
1
2
3
4
5
<!-- weitere Formular-Elemente -->

<input type="hidden" value="wert" />

<!-- weitere Formular-Elemente -->

Als Beispiel wird von einem CMS ausgegangen, in dem die Benutzer die Möglichkeit haben, ihren Account zu löschen. Im Profil der Benutzer befindet sich ein Link dazu. Wenn man diesen anklickt, kommt man auf eine Seite, auf der man das Löschen bestätigen muss. Diese Seite sieht wie folgt aus:

 
HTML
1
2
3
4
<form action="delete_account.php"  name="delete" method="post">
  <input type="hidden" name="id" value="89" />
  <input type="submit" value="Ja, meinen Account löschen!" />
</form>

Die Datei delete_account.php hat folgenden Inhalt:

 
PHP
1
2
3
4
5
6
<?php
// Verbindung zur Datenbank

$sql = "DELETE FROM `users` WHERE `id` = ".$_POST['id'];
mysql_query($sql);
?>

Ein Angreifer könnte das Bestätigungsformular auf seinem PC abspeichern und die zweite Zeile wiefolgt verändern:

 
HTML
1
<input type="hidden" name="id" value="123" />

Wenn er nun diese Seite (auf seinem PC) aufruft und den Button anklickt wird nicht sein Account sondern der, mit der ID 123, gelöscht!
Aus diesem Grund sollten versteckte Formularfelder für solche sensiblen Daten nur verwendet werden, wenn überprüft wird, ob der Benutzer überhaupt berechtigt ist, die dem Inhalt des versteckten Feldes entsprechende Aktion durchzuführen.

Sessions

Bei der Verwendung von Sessions sollte folgendes beachtet werden:
Wenn der User die Verwendung von Cookies in seinem Browser aktiviert hat, wird die Session-ID in einem Cookie gespeichert. Wenn er dies nicht hat, wird sie einfach an den URL angehängt, um sie der nächsten Seite zu übergeben. Letzterer Fall stellt ein sehr großes Sicherheitsrisiko dar, denn wenn der Benutzer eine Seite geöffnet hat, auf der eine Session gestartet wurde, und nun von dieser aus eine andere Website besucht, wird eventuell der Referer (und damit die Session-ID des Users) mitgeloggt. Über die Session-ID kommen Dritte an Daten heran, die eigentlich nicht für sie bestimmt waren.

Eine Schutzmaßnahme dagegen wäre, PHP mit aktiviertem session.use_only_cookies zu konfigurieren, dann wird die Session-ID immer in einem Cookie gespeichert. Wenn ein Benutzer die Verwendung von Cookies in seinem Browser deaktiviert hat, schlägt das Starten einer Session fehl!

Weiterhin entsteht ein Sicherheitsrisiko, wenn die Session-ID auf dem Server unverschlüsselt übertragen wird.

Dazu:

Variabler Funktionsaufruf

Gerne verwendet wird ein "variabler Funktionsaufruf". Dabei wird dem PHP-Skript der Name einer Funktion übergeben, welche aufgerufen werden soll. Dies kann hilfreich sein, wenn man z. B. ein Gästebuch innerhalb einer einzigen PHP-Datei geschrieben hat und nun über den URL festgelegt werden soll, ob die Einträge angezeigt werden sollen oder ein neuer Eintrag verfasst werden soll.

Der URL könnte zum Beispiel so aussehen:
guestbook.php?do=display_entries

Und wiefolgt das Gästebuch:

 
PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function display_entries() {
    // ...
}

function new_entry() {
    // ...
}

$function = $_GET['do'];
$function();

Ein Angreifer kann den URL aber beliebig ändern. Z. B. so:
guestbook.php?do=phpinfo

Damit wird die Funktion phpinfo() aufgerufen und der Angreifer erhält wertvolle Informationen über den Webserver und die PHP-Installation.

Um sich vor einem solchen Angriff zu schützen sollten die übergebenen Parameter wiefolgt überprüft werden:

 
PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
function display_entries() {
    // ...
}

function new_entry() {
    // ...
}

// Prüfen was übergeben wurde
switch( $_GET['do'] ) {
    case "new_entry":
       $function = "new_entry";
       break;
    case "display_entries":
       $function = "display_entries";
       break;
    default:
       $function = "display_entries":
       break;
}

$function();

So ist es nur noch möglich, die Funktionen new_entry() und display_entries() aufzurufen.

Variabler Include

Sehr beliebt ist es, für eine Website eine Hauptdatei anzulegen, welche den HTML-Kopf und -Fuß enthält und die Seite, die aufgerufen werden soll (zum Beispiel das Impressum oder Gästebuch) in die Mitte der Hauptdatei einzubinden.

Die Links sehen dann etwa so aus:
index.php?action=imprint
index.php?action=guestbook

Und so der Code der PHP-Datei:

 
PHP
1
2
3
4
5
6
7
<?php
// HTML-Kopf

include( $_GET['action'].".php" );

// HTML-Fuß
?>

Diese Methode stellt ein sehr großes Sicherheitsrisiko dar: Ein Angreifer kann, indem er den URL-Parameter action verändert, eine beliebige PHP-Datei einbinden und so einen sehr großen Schaden anrichten.

Daher sollten alle Namen der Dateien, die eingebunden werden können, in einem Array gespeichert werden. Über den URL wird dann nicht mehr der Dateiname, sondern der Schlüssel des Array-Elementes, das den Dateinahmen enthält, übergeben.

Beispiel:

 
PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$files = array( "start" => "start.php",
                "..."   => "..."
               );
                      
// $_GET['action'] gesetzt?
if ( empty( $_GET['action'] ) ) {
    $key = "start";
} else {
    $key = $_GET['site'];
}

// Existiert die Datei, die eingebunden werden soll?
if ( !@file_exists( $files[$key] ) ) {
    echo "Error!";
} else {
    include( $files[$key] );
}

Link:

Schutz vor ScreenScraping durch CAPTCHAs

Angenommen, auf einer Webseite gibt es ein Umfrage-Skript. Es gibt unter anderem folgende "Angriffsmöglichkeiten":

  1. Jemand der die Umfrage verfälschen will, könnte einen Bot schreiben, der, über einen Proxy-Server, auf die Seite mit der Umfrage geht, eine bestimmte Option auswählt und die Umfrage abschickt. Danach wechselt er den Proxy-Server (um die IP-Sperre zu umgehen) und nimmt erneut an der Umfrage teil. Diese Schritte können beliebig oft wiederholt werden.
  2. Jemand, der die aktuellen Ergebnisse der Umfrage auslesen und auf seiner eigenen Homepage anzeigen lassen will, könnte ein PHP-Skript schreiben, das die Umfrage-Ergebnisse von der fremden Website herausfiltert und ausgibt. Das nennt man "ScreenScraping".

Sogenannte CAPTCHAs (Completely Automated Public Turing-Test to Tell Computers and Humans Apart) sind eine Lösung für das Problem. Sie dienen dazu, einen Menschen von einem Computer zu unterscheiden: Wenn jemand an der Umfrage teilnehmen will oder die Ergebnisse von dieser aufrufen will, wird eine Grafik mit einer verzogenen Zeichenfolge anzeigt (diese Grafiken sind für (die meisten) Bots nicht lesbar), welche der Benutzer in ein Feld eingeben muss.

Links:

Fremde PHP-Skripte

Beim Einsatz von fremden PHP-Anwendungen (Foren, Gästebücher etc.) sollten folgende Punkte beachtet werden:

  • Es sollten nur PHP-Anwendungen eingesetzt werden, die noch weiterentwickelt werden und dessen Entwickler auch so schnell wie mögich Sicherheits-Updates beim Bekanntwerden einer Sicherheitslücke veröffentlichen.
  • Neu erschienene Sicherheits-Updates sollten so schnell wie möglich installiert werden.
  • Versionsnummern im Copyright der PHP-Anwendung sollten (wenn die Nutzungsbedingungen es zulassen) grundsätzlich entfernt werden. Dies erschwert einen Angriff, da manche Sicherheitslücken nur in ganz bestimmten Versionen einer Anwendung existieren.

Speichern von Passwörtern

Bei einem Login-System zum Beispiel müssen die Passwörter der Benutzer in einer Datei/Datenbank gespeichert werden. Um die Passwörter zu schützen (falls ein Angreifer sich Zugriff auf den Speicherort der Passwörter verschafft), sollten sie nicht im Klartext, sondern als Hash abgespeichert werden, zum Beispiel als md5-Hash.

Beispiel: Die Abfrage, um den Benutzernamen und das Passwort bei der Registration in der Datenbank zu speichern, könnte wiefolgt lauten (um den md5-Hash des Passworts zu erhalten wird die PHP-Funktion md5 verwendet):

 
PHP
1
2
3
4
$user = $_GET['user'];
$pw   = md5( $_GET['pw'] );

$sql = "INSERT INTO `users` (`username`, `password`) VALUES ('$user', '$pw')";

Wenn sich nun ein Benutzer einloggen will, wird der md5-Hash des eingegebenen Passwortes erstellt und mit dem aus der Datenbank verglichen:

 
PHP
1
2
3
4
$user = $_GET['user'];
$pw   = md5( $_GET['pw'] );

$sql = "SELECT `username` FROM `users` WHERE `username` = '$user' AND `password` = '$pw'";

Ein Nachteil dieser Methode ist, dass es nicht mehr möglich ist, einem Benutzer sein Passwort per E-Mail zu schicken, wenn er dieses vergessen hat. Stattdessen muss ein neues generiert und ihm zugeschickt werden.

Link:

Schutz von E-Mail-Adressen

Versender von Spammails lassen oft Bots durch das Internet "laufen", die wahllos auf Webseiten nach E-Mail-Adressen suchen, um an diese Spamnachrichten verschicken zu können.

Um sich davor zu schützen, können E-Mail-Adressen zum Beispiel. etwas "verschlüsselt" ausgegeben werden: email [ at ] host [ dot ] com anstelle von email@host.com, allerdings durchschauen die meisten Bots das.
Eine sicherere Methode, E-Mail-Adressen zu schützen, ist es, sie als Bild darzustellen.

Weder die "verschlüsselte" E-Mail-Adresse noch das Bild sollten allerdings verlinkt werden, denn Bots, die nach E-Mail-Adressen suchen, analysieren nicht die Ausgabe des Browsers, sondern den Quellcode der HTML-Datei.
Hierfür gibt es allerdings eine sichere Alternative, es kann mittels PHP ein Header an den Browser gesendet werden:

 
PHP
1
header( "Location: mailto:" .$mail );

Fazit

Es wurde hier ein Überblick über einige Askpekte der Entwicklung von sicheren PHP-Web-Applikationen verschafft. Zur Erweiterung des Wissens bieten sich unter anderem die am Ende eines Kapitels aufgelisteten Links. Auch Diskussions Foren zum Thema PHP (zum Beispiel das Skriptsprachen-Forum von Webmasterpro) können eine gute Quelle für weiteres Wissen sein, insbesondere aber Foren, die sich speziell mit der sicheren Entwicklung befassen, zum Beispiel das PHP - Security-Forum der DevNetwork Foren.

Weitere Websites, die sich mit der Sicherheit von PHP-Web-Applikationen befassen:

Eine Auswahl an sowohl deutsch- als auch englischsprachiger Literatur zur Sicherheit von PHP-Web-Applikationen findet sich bei Amazon.de.

Einige Beispiele:

Weiterhin sollte man regelmäßig einen Blick auf die heise Security News werfen.


Kommentare: Sichere PHP-Web-Applikationen schreiben - Ein Überblick

Neuen Kommentar schreiben
Qualitaetssicherung
Beantworten

Die Hinweise in diesem Tutorial sind sicher gut - keine Frage.

Ich kann nur hoffen, dass sich niemand diesen Stil der komplett fehlenden Qualitaetssicherung - auch ein garant fuer sichere Webapplicationen - aneignet.

gemeint ist das fehlende ueberpruefen von request-parametern und dessen einfaches verwenden, merke: isset()

Daniel Hanke am 25.02.2009 um 13:55
PHP IDS
Beantworten

Vielleicht wäre ein Link zu http://php-ids.org/ auch ganz nett.

Patrick Freitag am 28.10.2008 um 13:14
Speichern von Passwörtern...
Beantworten

Ich habe gerade den artikel überflogen, und bin in dem teil "Speichern von Passwörtern" über den md5 gestolpert.

Zwar vermittelst du einen richtigen Ansatz, allerdings gilt der md5() Hash nicht mehr als sicher, da für ihn mittlerweile äußerst umfangreiche Rainbowtables existieren, und er Verhältnismäßig leicht zu knacken ist. Besser ist an dieser Stelle der sha256 hash. Noch besser wird es, wenn das PW erst gesalzt und dann gehasht wird.

Unschön fand ich aber deinen Beispielcode, nicht wegen dem md5 sondern, wegen der ungeprüften übergabe des $_GET['user'] Parameters. Das ist somit ein Super Beispiel für SQL-Injections. Wenn du eine Artikel über sicheren Code schreibst, und SQL-Injections kennst, solltest du auch sichere Beispiele verwenden, und nicht den Fehler, den du in dem einen Kapitel beschreibst in einem anderen machen ;).

Jola am 29.08.2008 um 17:20
Re: Speichern von Passwörtern...
Beantworten

Zwar vermittelst du einen richtigen Ansatz

Mehr wollte ich auch nicht.

allerdings gilt der md5() Hash nicht mehr als sicher, da für ihn mittlerweile äußerst umfangreiche Rainbowtables existieren, und er Verhältnismäßig leicht zu knacken ist. Besser ist an dieser Stelle der sha256 hash. Noch besser wird es, wenn das PW erst gesalzt und dann gehasht wird.

Das stimmt. Der md5-Hash eignet sich meiner Meinung nach aber dennoch, um in das Thema einzuführen. Für alles weitere habe ich einen Artikel verlinkt, der sich genauer mit dem Thema beschäftigt und ich weise den Leser auch am Ende meines Artikels darauf hin, dass er sich die Links anschauen sollte.

Unschön fand ich aber deinen Beispielcode, nicht wegen dem md5 sondern, wegen der ungeprüften übergabe des $_GET['user'] Parameters. Das ist somit ein Super Beispiel für SQL-Injections.

Das ist mir bewusst. Ich habe aber nicht "100% fertige Lösung" über den Code-Schnippsel geschrieben, sondern "Beispiel" und als ein solches will ich es übersichtlich halten und deswegen nur das zeigen, was in dem Kapitel relevant ist. Ich gehe davon aus, dass der Leser sich merkt, was er wenige Minuten zuvor gelesen hat und dies daher realisiert.

Corvin Gröning am 29.08.2008 um 18:41
Re: Speichern von Passwörtern...
Beantworten

Der md5-Hash eignet sich meiner Meinung nach aber dennoch, um in das Thema einzuführen.

AFAIK ist es beim Speichern von Passwörtern derzeit auch noch nicht wirklich wichtig MD5 zu meiden, durch die kurzen Eingaben ergeben sich weniger Angriffsflächen (oder so). Außerdem muss man weiterhin das Passwort als MD5-Hash kennen. Wenn ein Angreifer so weit kommt liegt bereits einiges im Argen. ;-)

David Danier am 01.09.2008 um 15:41
Re: Speichern von Passwörtern...
Beantworten

der artikel wäre eigtl ein typischer wiki-artikel. sehr schön gemacht, denke aber dass ein artikel über php-sicherheit auch die bestmögliche sicherheit vermitteln sollte.

is wohl der längste artikel den wir zZ haben? :)

meggs am 01.09.2008 um 17:37
Super Artikel
Beantworten

Wirklich toller und sehr umfangreicher Artikel. Vielen Dank an Dich Corvin, vielleicht lesen wir in der Zukunft ja noch mehr von Dir hier.

Fabian Ziegler am 29.08.2008 um 15:18
SQL-Injections...
Beantworten

...sind meines Wissens nach mit PHP 5 in der Form wie oben angegeben nicht mehr möglich, da seit PHP 5 keine SQL-Strings mit Semikolons mehr akzeptiert werden. Eine solche Eingabe verursacht nur eine Fehlermeldung über einen Fehler in der SQL-Syntax.

Thomas Rix am 29.08.2008 um 11:10
Re: SQL-Injections...
Beantworten

Vielen Dank für den Hinweis. Ich habe ein anderes Beispiel gewählt.

Corvin Gröning am 29.08.2008 um 19:51
Verweise
Beantworten

Zu vielen der besprochenen Themen gibt es hier bereits Artikel, wäre schön wenn du an den entsprechenden Stellen darauf hinweisen würdest.

christian am 29.08.2008 um 00:17
Re: Verweise
Beantworten

Den Artikel über Register Globals und den über XSS hatte ich bereits verlinkt. Den über includes und das sichere Speichern von Passwörtern hatte ich vergessen. Habe ich ausserdem noch einen Artikel vergessen?

Corvin Gröning am 29.08.2008 um 00:24
hübsch
Beantworten

recht umfangreicher und informativer Beitrag - da mir die meisten Fakten bekannt sind habe ich leider nur das meiste überflogen. vor allem den bereich um die session ids würde ich mir etwas ausgeprägter wünschen da mir hier selbst noch das know how fehlt.

Benutzer gelöscht am 28.08.2008 um 21:50
Magic Quotes
Beantworten

Ich hab das meiste jetzt nur überflogen und kann dir in der Regel zustimmen, ABER:

magic_quotes_gpc und addslashes sind zur Vermeidung von SQL-Injections nur bedingt sinnvoll, vor allem sollte man sich nicht darauf verlassen. Besser sind hier die datenbankspezifischen Funktionen wie mysql_real_escape_string.

Auch verschwinden die magic quotes mit PHP 6 aus PHP.

Holger V am 28.08.2008 um 19:43
Re: Magic Quotes
Beantworten

Danke für den Hinweis. Ich hab's geändert.

Corvin Gröning am 28.08.2008 um 20:29