kungschu: SQL-Injection

Hallo Forum.

Obwohl ich schon einige Quellen (z.B.:http://de3.php.net/function.mysql-real-escape-string oder http://de.wikipedia.org/wiki/SQL-Injektion) besucht habe, bin ich mir noch nicht sicher, ob ich verstanden habe, wie ich eine SQL-Injection verhindere.

Ich habe es bisher so aufgefasst:

-Alle Daten, die ich in einer Datenbank ablegen möchte, sollte ich mit mysql_real_escape_string() maskieren.

-Damit es nicht zu "doppelter Maskierung" kommt, wende ich vorher stripslashes() an. (für den Fall, dass magic_quotes_gpc ON ist)

-Ein einfaches Beispiel (für einen sicheren Query) könnte also sein:

  
 <?php  
  
 if (isset($_POST['submit'])) {  
  
    $connection = mysql_connect('host','user','password');  
  
    $db = mysql_select_db('db', $connection);  
  
    if(get_magic_quotes_gpc()) {  
  
        $neuerInhalt = stripslashes($_POST['neuerInhalt']);  
  
    }else{  
  
        $neuerInhalt = $_POST['neuerInhalt'];  
  
    }  
  
    $neuerInhalt = mysql_real_escape_string($neuerInhalt);  
  
    $sql = "INSERT INTO table VALUES ('$neuerInhalt')";  
  
    mysql_query($sql, $connection);  
  
 }  
 ?>  

-Eine Abfrage zur Ausgabe von Daten (SELECT) muss grundsätzlich "nicht gesichert" sein.? Dabei besteht keine Möglichkeit zu einer SQL-Injection. (Es sei denn, auch eingegebene Daten, wie etwa Username und Password spielen eine Rolle)

Beuge ich somit einer SQL-Injection vor?
Sind alle "vier Punkte" richtig interpretiert?
Was sollte ich noch beachten?
Welche Fehler hat mein Beispiel-Code?

Herzlichen Dank.

MfG, Kungschu.

  1. Hi!

    -Eine Abfrage zur Ausgabe von Daten (SELECT) muss grundsätzlich "nicht gesichert" sein.? Dabei besteht keine Möglichkeit zu einer SQL-Injection.

    Doch. Immer wenn du Daten von außen in deine Abfrage einbaust, könnte auch beim SELECT eine Injection stattfinden.
    Du hast doch oben noch geschrieben, daß du den Wikipedia-Artikel gelesen hättest.
    Dort findest du doch genau solche Beispiele.

    Und in der Beschreibung von mysql_real_escape_string() im PHP-Handbuch findest du auch noch einen Link, der dir mehr zu SQL-Injections sagt.

    Schöner Gruß,
    rob

    1. Hallo.

      -Eine Abfrage zur Ausgabe von Daten (SELECT) muss grundsätzlich "nicht gesichert" sein.? Dabei besteht keine Möglichkeit zu einer SQL-Injection.
      Doch. Immer wenn du Daten von außen in deine Abfrage einbaust, könnte auch beim SELECT eine Injection stattfinden.

      Was heißt nun "Daten von außen"? Ich habe es so verstanden: Wenn ich etwa Username und Password mit einem DB-Eintrag vergleichen möchte, muss ich natürlich escapen, da ja (die zu vergleichenden) Usereingaben "von außen" kommen.

      Frage ich hingegen einfach nur Inhalt zur Ausgabe ab, besteht die Gefahr nicht. Zum Beispiel:

        
      [...]  
      $connection = mysql_connect('host','user','password');  
      $db = mysql_select_db('db', $connection);  
        
      $sql = "SELECT neuerInhalt FROM table";  
        
      mysql_query($sql, $connection);  
      [...]  
      
      

      MfG, Kungschu.

      1. Hi!

        Frage ich hingegen einfach nur Inhalt zur Ausgabe ab, besteht die Gefahr nicht. Zum Beispiel:

        [...]
        $connection = mysql_connect('host','user','password');
        $db = mysql_select_db('db', $connection);

        $sql = "SELECT neuerInhalt FROM table";

        mysql_query($sql, $connection);
        [...]

          
        Richtig. In diesem Fall besteht keine Gefahr.  
        Wie sollte man denn dort auch einen Angriff per SQL-Injection starten?  
        Du baust keinerlei Usereingaben (Daten, die von außen an dein Script geschickt werden) in dein Query ein.  
          
        Das hat aber nichts mit dem SELECT zu tun, daß du da nichts absichern mußt.  
        Bei einem UPDATE, DELETE, INSERT müßtest du in so einem Fall dort auch nichts absichern.  
        Wenn du deine Abfrage selber schreibst und keinerlei Usereingaben in dein Query einbasut, dann gibt es dort ja auch keine Angriffsmöglichkeit.  
        Wie sollte man dir denn dort irgendwelche Daten unterjubeln?  
          
        Schöner Gruß,  
        rob
        
        1. Hallo rob.

          Richtig. In diesem Fall besteht keine Gefahr.
          Wie sollte man denn dort auch einen Angriff per SQL-Injection starten?
          Du baust keinerlei Usereingaben (Daten, die von außen an dein Script geschickt werden) in dein Query ein.

          Korrekt. So hatte ich es auch verstanden.

          Das hat aber nichts mit dem SELECT zu tun, daß du da nichts absichern mußt.
          Bei einem UPDATE, DELETE, INSERT müßtest du in so einem Fall dort auch nichts absichern.
          Wenn du deine Abfrage selber schreibst und keinerlei Usereingaben in dein Query einbasut, dann gibt es dort ja auch keine Angriffsmöglichkeit.
          Wie sollte man dir denn dort irgendwelche Daten unterjubeln?

          Also. Ich resümiere:
          Ein Query ist nur dann gegen eine SQL-Injection abzusichern, wenn in irgendeiner(!) Form Usereingaben verwendet werden sollen / müssen.

          Habe ich beispielsweise einen passwortgeschützten Admin-Bereich, etwa für einen Blog, muss ich, auch wenn die Daten sicher nur von mir stammen können, gegen eine SQL-Injection vorgehen, da es sein könnte, dass Daten von einem fremden Formular an mein Script gesendet werden.

          Sprich: Ist GET oder POST im Spiel, muss ich vorbeugen!?

          MfG, Kungschu.

          1. Hiho!

            Sprich: Ist GET oder POST im Spiel, muss ich vorbeugen!?

            Ich glaube, das ist eine kurze aber auf den Punkt gebrachte Definition. Rein theoretisch ist es natuerlich moeglich, allein ueber einen Link in einem CMS oder einem 'Weiterbutton' eine Injection zu starten, da von dort immer irgendeine Variable kommt, die ausgewertet wird. Diese kann, da clientseitig, natuerlich immer manipuliert und eventuell missbraucht werden.

            Das wiederum koennte sich umgehen lassen, indem man mit Sessions arbeitet und dem Client gar nicht mitteilt, was man so fuer Variablen braucht. Wenn der Client nur ein 'Weiter' sendet und nicht ein ID=02 gibt es dort auch keine Angriffsmoeglichkeiten, trotz get/post.

            1. Hallo Steel.

              Danke dir für deinen Beitrag. So ist mir das Ganze nun einigermaßen klar geworden.

              MfG, Kungschu.

              1. Hey Kungschu»»

                Danke dir für deinen Beitrag. So ist mir das Ganze nun einigermaßen klar geworden.

                Ach... Dafuer doch nicht... *rotwerd*

  2. echo $begrüßung;

    -Alle Daten, die ich in einer Datenbank ablegen möchte, sollte ich mit mysql_real_escape_string() maskieren.
    -Damit es nicht zu "doppelter Maskierung" kommt, wende ich vorher stripslashes() an. (für den Fall, dass magic_quotes_gpc ON ist)

    Die Magic-Quotes stören nicht nur beim Eintragen in eine Datenbank, sondern auch an einigen anderen Stellen, beispielsweise wenn sie zwecks Fehlerkorrektur oder anderweitiger Ausgabe auf einer Webseite landen sollen oder in einer E-Mail. Es ist ungünstig, für all diese Anwendungsfälle die magic_quotes_gpc()-Prüfung und Entslashung einzeln durchzuführen. Stattdessen ist es günstiger die Eingabedaten generell und einmalig am Scriptanfang von den Magic Quotes zu befreien. Du hast es dann auch beim Umstieg auf PHP6 einfacher, denn da gibt es das Feature nicht mehr und dein Quelltext muss nur an einer Stelle bearbeitet werden statt an vielen. Ein Beispiel für eine zentrale Funktion gibts im Handbuch-Kapitel Disabling Magic Quotes

    echo "$verabschiedung $name";

    1. Hallo.

      Es empfiehlt sich also, grundsätzlich immer mit stripslashes() zu filtern?

      MfG, Kungschu.

      1. echo $begrüßung;

        Es empfiehlt sich also, grundsätzlich immer mit stripslashes() zu filtern?

        Es empfiehlt sich vor allem, das Feature Magic Quotes zu deaktivieren, am besten schon in der Konfiguration von PHP oder per Verzeichnis im Apachen. Nur wenn das nicht geht, oder man Scripte schreibt, die man zu verteilen gedenkt und die Bedingungen auf den Zielservern nicht kennt, empfiehlt es sich die Gegenmaßnahme in das Scrpt einzubauen, das aber zentral und nicht überall verstreut.

        echo "$verabschiedung $name";