Michael: mysql_real_escape_string oder magic_quotes_gpc

Hallo,

bisher war ich der Meinung, dass ich meine PHP Skripte durch das Setzen von magic_quotes_gpc=ON vor Fremdcodeeinschleusung bei SQL Statements hinreichend geschützt hätte. Denn einfache und doppelte Anführungszeichen und Backslash wurden ja stets escaped.

Jetzt habe ich aber im Netz gelesen, dass man stets die PHP Funktion mysql_real_escape_string nutzen sollte, um das SQL Statement abzusichern.

Leider könnte ich nirgends einen wirklich sicherheitsrelevanten Grund dafür nachlesen.

Reicht also weiterhin magic_quotes_gpc=ON aus?

Oder sollte ich alle Skripte jetzt mit mysql_real_escape_string() absichern?

Danke im Voraus für eure Hilfe!

Beste Grüße
Michael

  1. Moin!

    bisher war ich der Meinung, dass ich meine PHP Skripte durch das Setzen von magic_quotes_gpc=ON vor Fremdcodeeinschleusung bei SQL Statements hinreichend geschützt hätte. Denn einfache und doppelte Anführungszeichen und Backslash wurden ja stets escaped.

    Jetzt habe ich aber im Netz gelesen, dass man stets die PHP Funktion mysql_real_escape_string nutzen sollte, um das SQL Statement abzusichern.

    Das ist korrekt.

    Leider könnte ich nirgends einen wirklich sicherheitsrelevanten Grund dafür nachlesen.

    Den kann ich dir liefern. :)

    magic_quotes_gpc ist ein Mechanismus, der ausschließlich auf vom User übermittelte Daten wirkt, die sich in $_GET, $_POST und $_COOKIE befinden. Angewandt wird auf jeden übermittelten String jeweils die Funktion addslashes(). Diese Funktion fügt laut Dokumentation dem einfachen und dem doppelten Anführungszeichen (' und "), dem Backslash selbst () sowie dem NUL (das Null-Byte) einen Backslash davor.

    Magic_quotes_gpc wirkt aber beispielsweise nicht bei vom Skript "errechneten" Daten, die aus anderen Quellen kommen könnten. Und diese Backslashes in den Strings von $_GET, $_POST und $_COOKIE können durchaus auch selbst störend sein, und man müßte dann wieder stripslashes() anwenden, um sie zu entfernen.

    Addslashes() hat aber absolut keine technische Verbindung zu Datenbanken. Klar wirken die Resultate der Funktion "erwünscht" auf Strings, die in SQL-Statements an die Datenbank gehen sollen, aber als grundsätzliche Regel sollte man doch lieber der Datenbankbibliothek überlassen, welche Zeichen eines Strings man zu escapen hat - die Datenbankbibliothek für den Zugriff kommt vom Datenbankhersteller, und der wird am allerbesten wissen, welche Zeichen "böse" sind und entschärft werden müssen.

    Deshalb nimmt man IMMER mysql_escape_string() bzw. mysql_real_escape_string(). Diese Funktion bewirkt: "mysql_real_escape_string() ruft die MySQL Bibliotheksfunktion mysql_escape_string auf, diese stellt den folgenden Zeichen einen Backslash voran: NULL, \x00, \n, \r, , ', " und \x1a." Allein dieser Text beweist ja, dass die Funktion _mehr_ Zeichen escapet, als addslashes().

    Und außerdem wendet man mysql_real_escape_string() immer ganz am Ende beim Zusammensetzen des SQL-Strings an, und nicht schon prophylaktisch beim Skriptstart, wie magic_quotes_gpc es tun würden. Man kann ja durchaus die Strings aus z.B. $_POST vor der Verwendung im SQL-String noch bearbeiten. Eventuell zusätzliche, dann nicht entschärfte, Zeichen hinzufügen, oder (unabsichtlich) mit stripslashes() die Wirkung aufheben, bevor der String im SQL landet.

    Magic_quotes_gpc ist außerdem bei informierten und fähigen Programmierern eine sehr unbeliebte Option, weil sie zwingend erforderlich macht, dass man sich bei jedem Skriptstart immer noch mal um die Escapes kümmern muß - und das in drei Arrays, unter umständen rekursiv durch mehrere Arrayebenen. Insbesondere, weil, wie oben gezeigt, der Zweck dieser Option sehr sinnlos ist. Für Datenbank-Escapes ist addslashes() nicht zu gebrauchen. Für Direktausgaben von Strings auf die erzeugte Webseite ist die Wirkung von addslashes() ebenfalls sinnlos, weil dort eben gerade KEINE Backslashes benötigt werden. Und für Ausgaben in Dateien werden Slashes im Allgemeinen ebenfalls nicht benötigt.

    Man hat mit magic_quotes_gpc=on also eigentlich in allen drei typischen Fällen (Schreiben in die Datenbank, Schreiben in eine Datei, Schreiben in den Browser) immer nur den Extra-Aufwand, immer noch stripslashes() extra anwenden zu müssen, um dadurch den puren Originalstring zu erhalten, den man dann nach den eigenen Erfordernissen eventuell noch einmal neu escapen muß.

    Reicht also weiterhin magic_quotes_gpc=ON aus?

    Nein. Das ist ein veralteter Mechanismus, der verhindern soll, dass sich blutige Anfänger Code zusammenschreiben, der von findigen Angreifen zum Verschrotten der Datenbank oder zum Umgehen von Schutzmechanismen ausgenutzt wird. Stichwort: SQL-Code-Injection. Da dieses Szenario aber durch magic_quotes_gpc nur mangelhaft erreicht wird, und sich zudem in vielen anderen Fällen sogar sehr störend auswirken kann (auch für blutige Anfänger, bei denen auf der Website dann eben jedes Anführungszeichen, was NICHT über eine Datenbank läuft, mit einem führenden Backslash ausgestattet ist), wird mittlerweile davon abgeraten, diese Option einzusetzen.

    Oder sollte ich alle Skripte jetzt mit mysql_real_escape_string() absichern?

    Das wäre sehr sinnvoll. Nur als Beispielszenario für die mangelnde Absicherung von magic_quotes_gpc:

    $sql = "SELECT felder FROM tabelle WHERE feld1='$inhalt' AND feld2='$_POST[suchwort]'";

    Mit magic_quotes_gpc wird lediglich feld2 "abgesichert" (aber nicht vollständig).

    Was aber ist mit $inhalt. Ein offenbar interner Wert. Ist wirklich gesichert, dass darin kein einziges einfaches Anführungszeichen erscheinen kann? Wenn das z.B. ein vom Redakteur anderswo frei wählbarer Kategoriename ist, und er definiert beispielsweise "Deppenapostropht's" - schon knallt's mit einem vermeidbaren SQL-Fehler. Ist zwar (noch) kein böser Schaden entstanden, aber der zu beweisende Punkt ist: Sowas wird von magic_quotes_gpc nicht abgefangen, sondern nur durch vernünftiges Escaping:

    $sql = "SELECT felder FROM tabelle WHERE feld1='".mysql_real_escape_string($inhalt)."' AND feld2='".mysql_real_escape_string($_POST['suchwort'])."'";

    Mit diesem SQL-String hat die Datenbank niemals Interpretationsprobleme.

    - Sven Rautenberg

    --
    My sssignature, my preciousssss!
    1. Hallo Sven,

      vielen Dank für deine sehr ausführliche Antwort. Ich werde fortan auf mysql_real_escape_string() umsteigen und deinen Rat befolgen.

      Nochmal vielen Dank!

      Beste Grüße
      Michael

    2. echo $begrüßung;

      Ergänzend zu Svens ausführlicher Antwort auch hier der Hinweis auf das Handbuchkapitel zu den Magic Quotes, das ebenfalls Sinn und Unsinn und Gegenmaßnahmen beschreibt.

      echo "$verabschiedung $name";