Ankündigung

Einklappen
Keine Ankündigung bisher.

Zugriff auf Datenbank per Klasse - Sicherheit etc.

Einklappen

Neue Werbung 2019

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

  • Zugriff auf Datenbank per Klasse - Sicherheit etc.

    Guten Tag liebe Gemeinde.
    Leider habe ich mich mit einem sehr wichtigen Thema php betreffend noch nicht genügend auseinandergesetzt (bzw bin jetzt erst dabei das zu tun): MySQL.
    Ich möchte einfach und sicher auf eine MySQL Datenbank zugreifen mittels einer selbstgeschriebenen Klasse (ohne viel schnickschnack).
    Ich habe mich bereits ein wenig im Internet schlau gemacht. Zum Beispiel dieses Exemplar: Der Aufbau einer flexiblen Datenbankklasse für PHP | CMS, Datenbanken, Frameworks, PHP | Dr. Web Magazin
    Sieht doch ganz gut aus, finde ich. Aber die Kommentare ganz unten machen mich ein wenig stutzig und so ganz verstehe ich sie auch nicht. So zujm Beispiel: Warum soll mysql_real_escape_string nicht reichen? Wenn ich es richtig verstanden habe, wird der String ordentlich escaped und macht somit einen Angriff schwerer bis zu unmöglich.
    Ich lese überall was unterschiedliches - mal, dass mysql_real_escape_string reicht, mal dass es nicht reicht.

    Wie greife ich nun sicher auf eine MySQL Datenbank zu und was muss meine Klasse beinhalten, damit sie sicher ist?

    Gruß faraday


  • #2
    mysql_real_escape_string() ersetzt nur z.B. ' durch \', sodass das ' nicht als im Befehl befindlichen Syntax angesehen werden kann und eingreift.

    Allerdings gibts noch andere SQL Injection Methoden!
    MfG
    ~Capfly

    Kommentar


    • #3
      mysql_real_escape_string() hilft dir nicht, wenn das betreffende Feld ein INT ist (das wird nämlich nicht gequotet), da kommt man immernoch mit sehr spezifischen Attacken durch.

      Die (m.W.) einzige Möglichkeit sich vor SQL-Injection zu schützen besteht in der Verwendung von Prepared Statements (wobei natürlich das SQL statement selbst natürlich ebenfalls sicher sein muß). am besten nimmt man dazu PDO oder MySQLi (beides native PHP-Klassen).

      Kommentar


      • #4
        Zitat von Dormilich Beitrag anzeigen
        mysql_real_escape_string() hilft dir nicht, wenn das betreffende Feld ein INT ist (das wird nämlich nicht gequotet), da kommt man immernoch mit sehr spezifischen Attacken durch.
        Aber wenn das Feld ein INT ist, benutz ich laut der Klasse des beigefügten Links sprintf mit %d. Oder etwa nicht...?

        Kommentar


        • #5
          Zitat von faraday Beitrag anzeigen
          Aber wenn das Feld ein INT ist, benutz ich laut der Klasse des beigefügten Links sprintf mit %d.
          Wo steht das, ich find's nicht. Alleine die Zeichenkette %d kommt schon auf der verlinkten Seite nicht vor und sprintf wird dort nur dazu verwendet, aus den Argumenten und dem SQL-Template die fertige Datenbankabfrage zu generieren.
          Meinungen, die ich geäußert habe, sind nicht notwendigerweise meine eigenen. Abweichungen von der deutschen Rechtschreibung unterliegen dem Urheberrecht, dürfen aber unter den Bedingungen von verwendet werden

          Kommentar


          • #6
            und wie sieht’s bei LIMIT aus?

            Kommentar


            • #7
              Absolut richtig.
              Wie ich den Code auf die Schnelle überblicke, tun sich hier mehrere Probleme auf:
              PHP-Code:
                  public function query($sql, array $args){

                  
              // Leere Werte für neue Benutzung
                  
              $this->args = array();
                  
              // Werte escapen und Übertragung in neues Array
                  
              foreach ($args as $key){
                  
              array_push($this->argsmysql_real_escape_string($key));
                  }
                  
              // Zusammenführung
                  
              array_unshift($this->args$sql);
                  
              $this->sql call_user_func_array('sprintf',$this->args);
                  
              $this->lastResult mysql_query($this->sql);
                  
              $this->affectedRows mysql_affected_rows();
                  } 
              1.
              foreach ($args) durchläuft hier alle Parameter, unabhängig, welchen Typ sie im Query-Formatstring zugewiesen bekommen. Das ist nicht fatal aber unnötig.
              Wichtig dabei ist, dass dieses Verfahren für String-Werte, die in Feldsettings ohne Hochkommata laufen, trügerische Sicherheit erzeugt.

              2. die eigentliche Sicherheit entsteht also aus real_escape auf der einen Seite, %d/%u auf der anderen Seite. Statt einer 2-Komponenten-Lösung wäre ein Verfahren über alle Parameter die bessere Variante.

              3. real_escape kommt wie so oft ohne DB-Connection. Das fällt einem spätestens auf die Füße, wenn mehrere Datenbanken/Verbindungen gleichzeitig verwendet werden.

              4. call_user_func_array braucht hier kein Mensch. > vsprintf

              5. Evtl. Fehler von mysql_query() werden nicht abgefangen - zumindest auf affected_rows könnte sich das auswirken.

              Fazit: Hier entstehen mehr Nachteile als Vorteile. Die Query ausserhalb der Methode zusammenzubauen, hielte ich hier für die sicherere Variante.


              Auf jeden Fall die Kommentare im Artikel lesen!

              Aber wenn das Feld ein INT ist, benutz ich laut der Klasse des beigefügten Links sprintf mit %d.
              Eigentlich ist das hinreichend. Wichtig ist, dass %d den Typ des Feldes in der Query repräsentiert, nicht den des erwarteten Wertes.

              Das Pro-Beispiel im Artikel demonstriert leider eindrucksvoll, wie mans nicht machen soll:

              PHP-Code:
              $args = array($id);

              $dbEx->query("SELECT * FROM `schlachtschiffe` WHERE `product_id` = %s"$args) OR $dbEx->debug(); 
              Die Query sagt: erwartet wird ein num. Typ (fehlende Hochkommata), nutzt aber %s, was einen String-Wert zulässt. Der Injection-Schutz läuft nur über real_escape. Wenn in $id jetzt 'product_id' steht, ergibt sich folgende Query:
              Code:
              SELECT * FROM `schlachtschiffe` WHERE `product_id` = product_id
              , die wirkungsvoll alle vorhandenen Datensätze ausliest.

              Wenn Du die Klasse nicht direkt überschauen kannst, hindert Dich aber auch niemand daran, die Werte bei der übergabe explizit auf INT zu casten:

              PHP-Code:
              (int) $_POST['id']; 
              --

              „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


              • #8
                Zitat von mimomamu Beitrag anzeigen
                Wo steht das, ich find's nicht. Alleine die Zeichenkette %d kommt schon auf der verlinkten Seite nicht vor und sprintf wird dort nur dazu verwendet, aus den Argumenten und dem SQL-Template die fertige Datenbankabfrage zu generieren.
                Es muss doch nicht vorkommen auf der Seite. Ich kanns ja dennoch mit sprintf benutzen. Ich mach einfach in dem SQL-Template für int-Werte ein %d und ersetze es durch einen INT-Wert im args-Array. Da sprintf dann %d ausschließlich als Integer versteht und auch ausgibt ist doch alles gut, oder versteh ich da jetzt was falsch?

                Kommentar


                • #9
                  Gegen das Schreiben einer DB-Klasse als Fingerübung ist ja nichts einzuwenden. Benutzen würde ich dann aber schon eher DBO oder mysqli.

                  wenn man UserID, Passwort, etc in Klartext einer Klasse übergibt hat man von Programmierung im Jahr 2010 nichst verstanden.
                  Man darf sich über diverse Angriffsszenarien dann halt einfach nicht wundern.
                  Kann dazu mal jemand Stellung nehmen? Wo liegt da eine Schwachstelle und wie macht man es besser?
                  PHP-Code:
                  if ($var != 0) {
                    
                  $var 0;

                  Kommentar


                  • #10
                    Zitat von faraday Beitrag anzeigen
                    Es muss doch nicht vorkommen auf der Seite. Ich kanns ja dennoch mit sprintf benutzen.
                    Dann habe ich dich falsch verstanden. Ich dachte du meinst die Klasse macht das selbständig.
                    Meinungen, die ich geäußert habe, sind nicht notwendigerweise meine eigenen. Abweichungen von der deutschen Rechtschreibung unterliegen dem Urheberrecht, dürfen aber unter den Bedingungen von verwendet werden

                    Kommentar


                    • #11
                      Zitat von Wolla Beitrag anzeigen
                      Kann dazu mal jemand Stellung nehmen? Wo liegt da eine Schwachstelle und wie macht man es besser?
                      Keine Ahnung. Ich weiß ehrlich gesagt auch nicht, was Walter mit
                      sondern behandelt ein Problem auch mit PHP4 über eine Exception, die man halt in PHP4 selber schreiben muss.
                      meint. Den Exception-Mechanismus kann man ja nun nicht nachbauen, wenn man als einziges Instrument Rückgabewerte nutzen kann. Oder meint er irgend ein krudes Error-Handling? Dann kommt der Fehler aber trotzdem immer an der selben Stelle an und läufty nicht durch die Kontexte wie bei echtem Exception-„Bubbling“.
                      --

                      „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


                      • #12
                        Also jetzt mal konkret: Wie macht man es denn nun richtig? :-/
                        Gruß fara

                        EDIT:
                        Zitat von nikosch Beitrag anzeigen
                        Das Pro-Beispiel im Artikel demonstriert leider eindrucksvoll, wie mans nicht machen soll:

                        PHP-Code:
                        $args = array($id);

                        $dbEx->query("SELECT * FROM `schlachtschiffe` WHERE `product_id` = %s"$args) OR $dbEx->debug(); 
                        Die Query sagt: erwartet wird ein num. Typ (fehlende Hochkommata), nutzt aber %s, was einen String-Wert zulässt. Der Injection-Schutz läuft nur über real_escape. Wenn in $id jetzt 'product_id' steht, ergibt sich folgende Query:
                        Code:
                        SELECT * FROM `schlachtschiffe` WHERE `product_id` = product_id
                        , die wirkungsvoll alle vorhandenen Datensätze ausliest.
                        Aber wenn ich weiß, dass es sich um einen Zahlenwert handelt, kann ich doch %d benutzen - dann muss es doch kein String sein. Oder hab' ich da irgendwas übersehen? :-/ Oder redest du davon, dass die einfach ein falsches Beispiel genutzt haben?

                        EDIT EDIT:
                        Okay, falsches Beispiel.^^
                        Aber mit %d kann ich die Klasse sicher anwenden, oder?

                        Kommentar


                        • #13
                          Mit den oben genannten Einschränkungen.
                          --

                          „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


                          • #14
                            Zitat von nikosch Beitrag anzeigen
                            Mit den oben genannten Einschränkungen.
                            Punkt 1 hab ich nicht so ganz verstanden *schäm*

                            Kommentar


                            • #15
                              Wie in 2) steht - die halbe Sicherheit resultiert aus %d im Formatstring. Wenn ich dort %s verwende, aber keien Hochkommata setze, nützt mit real_escape überhaupt nichts (Beispiel unten). Die foreach Schleife läuft aber über alle Eingabewerte, die in der Query verbaut werden und führt pauschal real_escape darauf aus. Das schadet echten numerischen Werten jetzt nicht, suggeriert aber eine Sicherheit, die eigentlich nur mit %d erreicht wird.

                              Prepared Statements machen das hier anders, indem sie für jeden übergebenen Wert den Typ angeben lassen, wie der Wert interpretiert werden soll.
                              --

                              „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

                              Lädt...
                              X