[PHP] SQL-Injections

  • Heute zeige ich euch, was eine SQL-Injection ist, und wie man sich davor schützt.


    Zuerst haben wir am Anfang eine PHP-Datei und eine MySQL-Datenbank. In der PHP-Datei sind ein paar Lücken, die wir Stück für Stück finden und schließen werden.


    Code der Datei ( nicht XHML valide, ich weiß ^^ :(


    Datenbank am Anfang:



    Rufen wir nun die Webseite auf, sehen wir die Blogs, darunter sind Links zu der “Vollansicht” des Textes. Nicht sehr hübsch, aber funktionierend.
    Was hierbei nicht beachtet wurde, ist der Parameter der “weiterführenden” Links, das “$_GET['id']“.


    Stellt euch mal vor, ihr ruft das wie folgt auf:

    Code
    http://eureseite.de/index.php?id=2"


    Könnt ihr ja mal machen, heraus kommt ein

    Code
    Warning: mysql_fetch_assoc() expects parameter 1 to be resource, boolean given in C:\Users\Tion\Desktop\Framework\htdocs\sqlinjection.php on line 12


    Hier würde man jetzt sehen, dass eine Lücke vorliegt. Und jetzt machen wir es noch mal eine Stufe anders und lesen gleich alles aus, um es uns dann wohl geordnet runterzuladen.

    Code
    http://eureseite.de/index.php?id=2 OR 1=1 INTO OUTFILE "C:/Users/Tion/Desktop/Framework/htdocs/database.txt"


    Den Pfad haben wir ja aus der Fehlermeldung oben, MySQL liest alles aus und speichert es in der “database.txt”. Und tada, das steht drinne:

    Code
    1 Testeintrag 2012-03-02 08:41:23 Hallo  
    Dies ist ein Testeintrag 
    2 Weiterer Eintrag 2012-03-02 08:42:25 Hier haben wir noch einen Eintrag


    Allerdings sollten wir uns langsam mal über die Sicherheit des Blockes klar werden :S
    Scheint auch harmlos zu sein, hat er alle Blogeinträge, soll er doch lesen. Der Spaß hört allerdings auf, wenn die Tabelle “user” mit Benutzer + Passwort + Zugriffsrechten ausgelesen wird und im Netz steht.


    Also, wie schützen wir uns dagegen ?
    Der magische Befehl lautet… mysql_real_escape_string. ( Bei SQLite-Benutzern: sqlite_escape_string ) Wir ändern also die Zeile

    PHP
    $query = 'SELECT * FROM `blockentrys` WHERE `id` = '. $_GET['id'];


    zu

    PHP
    $query = 'SELECT * FROM `blockentrys` WHERE `id` = "'. mysql_real_escape_string($_GET['id']) .'"';


    Und tada, der Blogeintrag wird wieder angezeigt, allerdings keine Datei mehr erzeugt.


    Für die, die allerdings keine Lust haben, jeden einzelnden “$_GET”- / “$_POST”- / “$_COOKIE”- Eintrag zu maskieren, können das ja in einer foreach-Schleife erledigen
    Den Code liefere ich euch mal:


    Anmerkung:
    Ich wurde in den Kommentaren in meinem Blogeintrag von deadinat0r darauf hingewiesen, dass auch array_map genutzt werden könnte.
    Der Code sähe dann etwa so aus:

    PHP
    $_GET = array_map('mysql_real_escape_string', $_GET);


    Quelle: tionsys.de