Ankündigung

Einklappen
Keine Ankündigung bisher.

Sql Injection durchführen?

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Sql Injection durchführen?

    Hallo,

    ich informiere mich momentan genauer über das Thema PHP und Sicherheit und habe mehrere Artiekl über Sql Injection u. ä. gelesen..

    Versuche nun des öfteren die dort gezeigten Beispiele nachzuvollziehen/auszuprobieren (natürlich nur auf eigene Scripte)

    Ausgangsscript ist z.B. bei mir:
    PHP-Code:
    $login_password $_POST[login_password];
    $login_mail $_POST[login_mail];

    $res "Select COUNT(id) as anzahl FROM benutzer WHERE mail = '".$login_mail."' AND password = '".$login_password."'";
        
    $sql mysql_query($res);
        
    $anzahl mysql_result($sql,"anzahl");
            if (
    $anzahl '0') { 
            echo 
    "Stufe 1";
    //.... 
    PS: Mir ist schon klar, dass ich erstens sofort die $_POST-Variable in die MySql-Anweißung schreiben könnte und ich alles in den Anführungszeichen schreiben kann...habs versuchsweiße so gemacht.

    Gebe ich für $_POST[login_password] = ."' OR 1=1; /* ein, kommt ein MySql Error.
    Gebe ich für '$_POST[login_password] = ; mysql_query(UPDATE benutzer set password = 2) passiert auch nichts.
    Und gebe ich md5("asdasd") ein gibt php bei der Ausgabe genau das gleiche aus...

    Wie gesagt, ich möchte nicht der Power-Hacker werden, möchte nur die Möglichkeiten und die Funktionsweiße verstehen und auch mal selber ausprobiert haben...

    Würde mich über eine Antwort, was ich bei diesen Beispielen falsch mache, freuen.

    EDIT: Eine andere Frage die mir gerade aufgekommen ist, da ich gerade eine kleine secure Klasse schreibe... ist es sinnvoller htmlspecialchars vor dem Speichern in die DB zu verwenden und später immer so ausgeben zu lassen oder doch lieber htmlentities beim speichern in di DB und bei der Ausgabe html_entity_decode verwenden? Oder anders gefragt, muss man nach der Speicherung von Strings in der DB bei der Ausgabe Angst haben, dass Fremdcode eingebunden wird?


    Grüße

    Matthiasnet


  • #2
    Bei aktiviertem magic_quotes wird nur addslashes() über die bekannten Super-Globalen, die vom User kommen ($_COOKIES, $_POST, $_GET, ??), ausgeführt.

    http://de.php.net/magic_quotes
    When on, all ' (single-quote), " (double quote), \ (backslash) and NULL characters are escaped with a backslash automatically. This is identical to what addslashes() does.
    Das ist allerdings zu wenig, denn um Daten in einen MySQL-Query zu platzieren, empfiehlt es sich, mysql_real_escape_string() anzuwenden:
    mysql_real_escape_string() ruft die Funktion mysql_real_escape_string der MySQL-Bibliothek auf, die folgende Zeichen mit einem Backslash ('\') versieht: \x00, \n, \r, \, ', " und \x1a.
    Offenbar hält MySQL also mehr Zeichen für gefährlich, magic_quotes wägt dich also in falscher Sicherheit. Denn woher soll PHP wissen, wo die Daten landen? Bei MySQL, in einer CSV Datei, in einer XML Datei, doch bei Oracle? Und jeder Datenspeicher benötigt eine andere Validierung, um Injections zu vermeiden. PHP kann es eben nicht allen Recht machen und empfiehlt daher, sich ganz rauszuhalten:
    It's preferred to code with magic quotes off and to instead escape the data at runtime, as needed.
    "as needed", also für MySQL -> mysql_real_escape_string

    Wenn du nun an einen Server-Hoster kommst, der diese empfohlene Einstellung übernimmt und magic_quotes deaktiviert und du immernoch munter $_GET und $_POST Daten in deine Querys brätst, weil "kümmert sich ja PHP drum", bist du komplett ungeschützt. Dann klappen auch deine altbackenen Tricks (allerdings nicht der, der auch noch PHP-Code enthält, denn PHP-Code kannst du so natürlich nicht einschleusen. Da müsstest du schon eval() oder ähnliches ausführen).

    Daher kümmer dich selbst um die Validierung und verwende zum Beispiel folgendes Konstrukt:

    PHP-Code:
    <?php
    function quoteSmart($value$connection)
    {
       if (
    get_magic_quotes_gpc()) { // mq aktiviert?
         
    $value stripslashes($value); // rückgängig machen!
       
    }
       return 
    mysql_real_escape_string($value$connection);
    }
    ?>
    $connection ist hierbei die von mysql_connect() zurückgelieferte Verbindungskennung. Schließlich könnten bei mehreren MySQL-Verbindungen auch verschiedene MySQL-Server laufen, die wiederum versionsabhängig unterschiedliche Zeichen escaped haben möchten.


    muss man nach der Speicherung von Strings in der DB bei der Ausgabe Angst haben, dass Fremdcode eingebunden wird?
    Ja, zum Beispiel wenn jemand JavaScript-Code einschleust. Ganz ärgerlich, denn der wird beim User (bei jedem der ihn aufruft) ausgeführt. Dieses könnte dann Cookies auslesen und an den Angreifer schicken.
    Vielleicht interessiert dich noch dieser Artikel
    http://www.phpfriend.de/forum/ftopic51631.html

    Kommentar


    • #3
      Danke für deine Antwort!
      Habe mir mal eine kleine Klasse und ein Testscript erstellt (achte nun auch darauf jede Vriable zu initialisieren, als ob register_globals=off wär).
      Wenn jemand kurz drüberschauen könnte und ein Feedback geben könnte, ob man damit sicher programmieren könnte, wär ich dankbar dafür.

      PHP-Code:
      class mysql 
      {
        var 
      $spalte='';
        var 
      $tabelle='';
        var 
      $dazugehoerige_werte='';
        var 
      $erfolgreich='';
        var 
      $sqlab='';
           function 
      insert ($tabelle,$spalten,$dazugehoerige_werte,$erfolgreich="Datensatz wurde erfolgreich hinzugefügt") {
                 
      $sqlab "
              INSERT INTO 
      $tabelle
              (
      $spalten)
              VALUES
              (
      $dazugehoerige_werte)";
               if (
      mysql_query($sqlab)) {
                  echo 
      $erfolgreich;
                  } 
               else {
                  echo 
      "Datensatz konnte nicht hinzugefügt werden.".mysql_error();
                  }
              }
      }



      class 
      sicherheit 
      {
          var 
      $string='';
          
          function 
      secure_text($string) {
          
      $string trim($string);    
          
      $string htmlentities($stringENT_QUOTES);    
          return(
      $string);
          }
          
          function 
      mysql_secure($string) {
          if(
      get_magic_quotes_gpc()) {
            
      $string stripslashes($string);    
          }
          
      $string mysql_real_escape_string($string);   
          
      $string sicherheit::secure_text($string);
          return 
      $string;
            }
          
          function 
      ausgabe($string) {
          
      html_entity_decode($string);
          return 
      $string;
          }    

      PHP-Code:
      //Testscript
      <?
      include("mysql.class.php");

      $eingabe1=$sicherheit->mysql_secure($_POST[eingabe1]);
      $eingabe2=$sicherheit->mysql_secure($_POST[eingabe2]);
      $sql = '';

      if (isset($_POST[senden]) && !empty($eingabe1) && !empty($eingabe2)) {

          echo 'Einfache Ausgabe der Eingaben mit secure_text:
      1:'.$sicherheit->secure_text($_POST[eingabe1]).'
      2:'.$sicherheit->secure_text($_POST[eingabe2]);
          echo '

      So wird die Eingabe in die DB gespeichert:
      1:'.$eingabe1.'
      2:'.$eingabe2."
      ";
          
          $mysql->insert("test","ein1, ein2","'$eingabe1' ,'$eingabe2'");
          $sql = $mysql->select("ein1, ein2","test","-","id Desc","1");
          while ($obj = mysql_fetch_object($sql)) {
              $ein1=$obj->ein1;
              $ein2=$obj->ein2;
          }
          
          
          echo '

      Ausgabe der Eingaben aus der DB:
      1:'.$sicherheit->ausgabe($ein1).'
      2:'.$sicherheit->ausgabe($ein2);

      }

      ?>
      <form action="<? $_SERVER['PHP_SELF']?>" enctype="multipart/form-data" method="POST">
      Eingabe1: <input name="eingabe1" size="30" value="<? echo $_POST[eingabe1]; ?>">

      Eingabe2: <input name="eingabe2" size="30"  value="<? echo $_POST[eingabe2]; ?>">


      <input name="senden" type="submit" value="Abschicken">
      </form>
      Link zum testen: http://www.lachenundspass.de/labor/sicherheitstest.php

      Hätte zusätzlich noch eine Frage, ob es sinnvoller(sicherer) wär als value Wert den validierten Code zurückzugeben oder kann man auch den eingegebenen ohne bedenken eingeben?

      Grüße

      Matthias

      Kommentar


      • #4
        Natürlich mußt DU auch auf die allg. Codequalität achten. Deshalb als erstes
        Code:
        error_reporting(E_ALL);
        Einiges ist vielleicht auch erst beim Posten entstanden. So ins Auge stechen mir:
        1. Script:
        - keine ausreichende Fehlerbehandlung (z.B. return false)
        - mysql_real_escape_string benutzt eine DB Verbindungsressource. Diese sollte der Methode bekannt sein, besser ists m.E. mysql_real_escape_string der mysql Klasse zuzuordnen
        - trim () halte ich nicht für Sicherheitsrelevant
        - htmlentities () nach mysql_real_escape_string () ist fragwürdig. Genau wie html_entity_decode () bei der Ausgabe. Warum nicht besser die Daten bei der Ausgabe erst encodieren
        - $string brauch in der Sicherheit Klasse nicht initialisiert werden, da Du rein statische Methoden nutzt
        - mysql Klasse: was soll $erfolgreich als Funktionsparameter?
        ...
        2. Script:
        - doppeltes <?
        - $_POST[senden]) -> senden ist keine Konstante
        - fehlendes ?>
        - ein evl. sql Fehler wird nicht behandelt. Damit wärem m.E. $ein1 und $ein2 auch nicht definiert

        In Deinem Online Bsp. werden z.B. Hochkommata bei Wiederaufruf gequotet wieder angezeigt, wenn ich das zweite Feld nicht angebe.
        --

        „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
        Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“


        --

        Kommentar


        • #5
          Zitat von Matthiasnet
          Hätte zusätzlich noch eine Frage, ob es sinnvoller(sicherer) wär als value Wert den validierten Code zurückzugeben oder kann man auch den eingegebenen ohne bedenken eingeben?
          Uffz, formulier den Satz mal ohne Doppelmoppel (value Wert, eingegebenen eingeben) - wer war das? Andreas Möller: "Vom Feeling her hab ich ein gutes Gefühl". Naja.

          Zunächst mal finde ich deine Klasse sehr lobenswert, zumindest dass du versuchst die üblichen Queries (SELECT, INSERT) zu automatisieren und in einer Methode zu kapseln.

          Wie immer habe ich jedoch einiges zu bemängeln:
          Grundsätzlich solltest du dann aber auch konsequent bleiben und die GESAMTE Arbeit der Methode überlassen. Sprich die Validierung auch von der Methode machen lassen.

          Weiteres:
          - Mix nicht Deutsch mit Englisch, so redet kein Mensch und so versteht den Code auch nur wer Englisch und Deutsch kann.
          - statische Methoden können nicht auf nicht-statische Objekteigenschaften zugreifen, lass also alles was du mit "var " deklariert hast weg.
          - Nach Anwendung von mysql_real_escape_string() solltest du den String nicht mehr manipulieren, er könnte sonst ungültig verändert werden.
          - MySQL führt meines Wissens nach automatisch ein TRIM() auf die Daten aus
          - Das Problem bei SQL-Injections oder überhaupt Injections ist, dass eigentlich als Daten bestimmte Werte plötzlich als Code interpretiert werden. Dies gilt es zu verhindern und mysql_real_escape_string() macht dies zuverlässig, jedoch eben nur, wenn du das Ergebnis nicht mehr manipulierst und genau das tust du. Zwar wahrscheinlich nicht schädlich, aber du tust es (Code1, Zeile 39/40, am besten beide vertauschen). Abgesehen davon ist es der Datenbank egal ob der String html-entity-encoded ist oder nicht.
          - dein insert() Methode sollte als Rückgabewert mysql_affected_rows() == 1 haben, damit du danach auch weißt oder prüfen kannst, ob die Werte eingetragen wurden
          - $mysql->insert("test","ein1, ein2","'$eingabe1' ,'$eingabe2'");
          du solltest die Daten atomar übergeben, dass heißt statt "ein1,ein2" ein array("ein1","ein2"). Das Ausschreiben in einen Array ist ein Mehraufwand, den man ja gerade verhindern möchte, daher kannst du auch mal Komma-separierte Werte übergeben. Ich würde dir aber raten diese nocheinmal von der Funktion exploden und wieder validiert zusammensetzen zu lassen. Allein schon um dem nächsten Punkt Rechnung zu tragen:
          - versuche sauberen SQL-Code zu erzeugen, wenn du ihn schon einmalig kapselst und zwar in dem du `Backticks` verwendest. So vermeidest du auch zusätzlich SQL-Injections

          Kommentar


          • #6
            Zitat von nikosch77
            1. Script:
            - keine ausreichende Fehlerbehandlung (z.B. return false)
            Hatte zuvor "or die()" benutzt, jedoch wird dies bei jeder Funktion ausgeführt, soabld kein Text vorhanden ist. False ja somit auch...
            Zitat von nikosch77
            - mysql_real_escape_string benutzt eine DB Verbindungsressource. Diese sollte der Methode bekannt sein, besser ists m.E. mysql_real_escape_string der mysql Klasse zuzuordnen
            Ok, aber eigentlich wär es doch egal, wenn man immer die gleiche MySql Verbindung geöffnet hat (dann wird ja auto. die zuletzt aufgebaute Verbindung benutzt)
            Zitat von nikosch77
            - trim () halte ich nicht für Sicherheitsrelevant
            Ist nun auch nur zur Überprüfung gedacht, ob nicht ejmand nru Leerzeichen verwendet hat... hat halt dazu gepasst, auch wenn es nicht direkt was damit zu tun hat.
            Zitat von nikosch77
            - htmlentities () nach mysql_real_escape_string () ist fragwürdig. Genau wie html_entity_decode () bei der Ausgabe. Warum nicht besser die Daten bei der Ausgabe erst encodieren
            Hab ich mal vertauscht, jedoch werden die Daten doch erst bei der Ausgabe encodiert, wie im Beispiel oder versteh ich was falsch?
            Zitat von nikosch77
            - $string brauch in der Sicherheit Klasse nicht initialisiert werden, da Du rein statische Methoden nutzt
            ok, danke
            Zitat von nikosch77
            - mysql Klasse: was soll $erfolgreich als Funktionsparameter?
            Je nach Bedarf (Anmeldung, NBewslettereintargung etc.) sollte eine andere Meldung bei erfolgreichem Anlegen des Datensatzes kommen...
            ...
            Zitat von nikosch77
            2. Script:
            - doppeltes <?
            - fehlendes ?>
            ist hier beim posten durcheinandergekommen....
            Zitat von nikosch77
            - $_POST[senden]) -> senden ist keine Konstante
            Hilft mir leider nicht weiter...gerade deshalb, weil es keine Konstante ist wollte man doch mit isset prüfe oder (laut php-manual) und bei Konstanten defined oder?
            Zitat von nikosch77
            - ein evl. sql Fehler wird nicht behandelt. Damit wärem m.E. $ein1 und $ein2 auch nicht definiert
            Also so?:
            PHP-Code:
            if (mysql_num_rows($sql)) {
                    while (
            $obj mysql_fetch_object($sql)) {
                        
            $ein1=$obj->ein1;
                        
            $ein2=$obj->ein2;
                    }
                }
                else {
                    
            $ein1=false;
                    
            $ein2=false;
                } 
            Zitat von nikosch77
            In Deinem Online Bsp. werden z.B. Hochkommata bei Wiederaufruf gequotet wieder angezeigt, wenn ich das zweite Feld nicht angebe.
            Danke, hab ich mit
            PHP-Code:
            <? echo stripslashes($eingabe1); ?>
            behoben.

            bzg.
            PHP-Code:
            error_reporting(E_ALL); 
            benutze ich zum ersten Mal und hab nun ehrlich gesagt keine Ahnung was da von mri verlangt wird...hab da schon alles möglich ausprobiert, kommen leider immer diese Fehlermeldungen http://www.lachenundspass.de/labor/sicherheitstest.php
            PHP-Code:
            $eingabe1=FALSE;
            $eingabe2=FALSE;
            $sql=FALSE;
            if (isset(
            $_POST[eingabe1])) {$eingabe1=$sicherheit->mysql_secure($_POST[eingabe1]);} else {$_POST[eingabe1]=false;}//Zeile 8
            if (isset($_POST[eingabe2])) {$eingabe2=$sicherheit->mysql_secure($_POST[eingabe2]);} else {$_POST[eingabe2]=false;}//Zeile 9
            if (isset($_POST[senden])) {$_POST[senden]=true;} else {$_POST[senden]=false;}//Zeile 10 

            Sorry wenn ich gerade leicht auf dem Schlauch stehe, hab bei google auch alles abgesucht, aber kam dabei zu keinem besseren Ergebnis als diesem...

            @Zergling...muss den Post erstmal durchlesen und es verstehne bevor ich drauf antworte, hattest geantwortet als ich shcon in der ANtwortfunktion war (braucht 40 min^^)

            Kommentar


            • #7
              Klar, keine Eile. Eben hab ich wohl versehentlich den Firefox geschlossen, daher Kurzfassung hier zum Thema
              Zitat von Matthiasnet
              Zitat von nikosch77
              - $_POST[senden]) -> senden ist keine Konstante
              Hilft mir leider nicht weiter...gerade deshalb, weil es keine Konstante ist wollte man doch mit isset prüfe oder (laut php-manual) und bei Konstanten defined oder?
              Notice: Use of undefined constant eingabe1 - assumed 'eingabe1' in /www/htdocs/w0074849/labor/sicherheitstest.php on line 8
              http://de.php.net/manual/de/language...es.array.donts

              Kommentar


              • #8
                Hallo,

                sooo erstmal danke für deine Vebesserungsvorschläge, übrigens finde ich es immer gut wenn jemand was zu bemängeln hat, dass ist der einzige weg etwas dazuzulernen und etwas optimal zu programmieren :wink:

                Führe deine Verbesserungen gerne durch, zum Thema bzg. trim(): Wird, wenn ich insert... im phpMyAdmin durchführe mit Leerzeichen gespeichert...also anscheinend doch nicht.
                du solltest die Daten atomar übergeben, dass heißt statt "ein1,ein2" ein array("ein1","ein2"). Das Ausschreiben in einen Array ist ein Mehraufwand, den man ja gerade verhindern möchte, daher kannst du auch mal Komma-separierte Werte übergeben.
                Da blick ich leider nicht ganz durch...ich sollte statt "ein1,ein2" ein array verwenden...jedoch schreibst du ancher, dass das ausschreiben in einem array Mehraufwand ist?

                Wegen der Validierung in der Methode, hatte ich mir auch überlegt das ganze erst dort durchzuführen und hatte es soweit umgesetzt, jedoch sind die Variablen, werden diese in der Methode einegfügt, noch nicht validiert worden... somit ist doch eig. wieder ein Sicherheitsmangel, da man ohne weiteren die Methode schließen könnte und was anderes ausführen könnte oder??
                Alternativ würde mir einfallen, dass die Daten zu beginn normal vbalidiert werden und bei einem Query nochmal extra für mysql validiert werden...meinst du zufällig das?

                Ansonsten war der Link sehr hilfreich...wusste ich zuvor noch gar nicht.[/code]

                Kommentar


                • #9
                  Ja ist halt so die Frage ob man sich eher an die Richtlinie halten möchte, Daten atomar zu übergeben oder ob man lieber kurz und knackig Code schreibt. Ich machs meistens so, dass ich beides akzeptiere und den String dann vor dem eigentlichen Funktionsblock in einen Array umwandle.

                  Etwa so:
                  PHP-Code:
                  <?php
                  function doSomething($var)
                  {
                    if (
                  is_string($var)) {
                      
                  $var array_map('trim'explode(','$var));
                    }
                    
                  // funktionsblock
                  }
                  ?>
                  So kann ich halt
                  PHP-Code:
                  <?php
                  doSomething
                  ('eins,zwei,drei');
                  // oder
                  doSomething(array('eins','zwei','drei'));
                  ?>
                  verwenden. Persönlich finde ich die erste Variante halt unschön, dafür ist sie eben kürzer und vielleicht auch übersichtlicher.

                  Ist aber vielleicht auch so ne Sache, wo man sich als Programmierer viel zu viel unsinnige Gedanken machen kann

                  Kommentar


                  • #10
                    mhh..letztendlich muss ich jedoch das array mit z.B. implode wieder zusammenfügen, damit ich es in der select-Anweißung angeben kann oder? Kenne keine Funktion die das ganze Array ohne Schleifen komplett ausgeben kann... oder verstehe ich was falsch?

                    Kommentar


                    • #11
                      edit

                      Kommentar

                      Lädt...
                      X