Wurzelzwerg: Sichern einer MySQL-Datenbank in PHP

Hallo allerseits,

mit dem Befehl "SHOW CREATE TABLE tabellenname" kann ich mir quasi ein Dump einer Tabellenstruktur machen. Wie kriege ich einen Dump des Inhalts hin?? Ich möchte gern, daß mir der Inhalt Zeile für Zeile so präsentiert wird:

INSERT tabellenname SET (Wert1,Wert2,...Wertn);

Natürlich könnte ich das mit "Select * FROM ..." hinkriegen indem ich die Feldinhalte zum gesuchten String zusammenbaue, aber dabei sehe ich mindesten 2 Probleme. 1. muß ich rauskriegen, welches Feld eine Zeichenkette ist, damit ich den Feldinhalt in "'" setzen kann. 2 müssen ja bestimmte Zeichen in der "Insert"-Anweisung konvertiert werden, ein Zeilenumbruch wird z.B. zu "\n" usw., wobei hier ja die Gefahr besteht, daß man Zeichen vergißt, wenn man das per selbstgestricktem Programm erledigt. Gibt es da nicht auch eine Möglichkeit, das Gesuchte (also den Tabelleninhalt schon "fertig aufbereitet") über einen MySQL-Befehl zu bekommen ??

vielen Dank schonmal

  1. Hi Wurzelzwerg,

    mit dem Befehl "SHOW CREATE TABLE tabellenname" kann ich mir quasi ein Dump einer Tabellenstruktur machen. Wie kriege ich einen Dump des Inhalts hin?? Ich möchte gern, daß mir der Inhalt Zeile für Zeile so präsentiert wird:

    INSERT tabellenname SET (Wert1,Wert2,...Wertn);

    Meines Wissens gibt es keinen SQL Befehl, der dir die fertigen Inserts ausspuckt - in meiner MySQL DB-Export Klasse holt sich das Script die einzelnen Daten auch über SELECT und bastelt den INSERT Befehl dann manuell zusammen.

    Auf die gleiche Weise macht es AFAIK auch PHPMyAdmin.

    MfG, Dennis.

    1. Hey, dank Dir. Das ist vermutlich das, was ich suche. Hatte also schon jemand vor mir das Problem ;)
      Ich werde es heute abend gleich mal testen ;)

      viele Grüße und vielen Dank

    2. echo $begrüßung;

      in meiner MySQL DB-Export Klasse

      ... habe ich Verbesserungspotential gefunden.

      Der Tippfehler in Zeile 72 ("Verbdingung") ist nicht weiter tragisch. Was aber eine Klasse, die man in anderen Projekten wiederverwenden möchte, nicht tun sollte, ist, einfach das komplette Script sterben zu lassen, wenn ein Fehler auftritt. Stattdessen sollte man das dem aufrufenden Programmteil mitteilen und diesem dann die aus dessen Sicht geeigneten Maßnahmen überlassen. Für dieses Mitteilen gibt es mehrere Möglichkeiten. Die beste wäre eine Exception zu werfen, was aber erst seit PHP5 geht. Eine weitere wäre, über den Rückgabewert der aufgerufenen Methoden mitzuteilen, dass ein Fehler aufgetreten ist. Das kann man zum Beispiel durch Übergabe eines simplen false oder eines Error-Objekt tun. Letzteres wird in PEAR so gehandhabt.

      Die übergebenen Parameter für Datenbank- und Tabellennamen werden nicht maskiert, was man unter Umständen für SQL-Injection ausnutzen kann.

      echo "$verabschiedung $name";

      1. Hi dedlfix,

        Was aber eine Klasse, die man in anderen Projekten wiederverwenden möchte, nicht tun sollte, ist, einfach das komplette Script sterben zu lassen, wenn ein Fehler auftritt. Stattdessen sollte man das dem aufrufenden Programmteil mitteilen und diesem dann die aus dessen Sicht geeigneten Maßnahmen überlassen.

        Stimmt - da hast du natürlich recht, ich habe es jetzt so gemacht, dass in $instanz->error die letzte Fehlermeldung gespeichert wird und die Funktionen im Fehlerfall false zurück liefern.

        Die übergebenen Parameter für Datenbank- und Tabellennamen werden nicht maskiert, was man unter Umständen für SQL-Injection ausnutzen kann.

        Hm, eine ernste Sache, die du da ansprichst - erst mal vorweg, denkst du wirklich jemand könnte auf die Idee kommen, die Export Klasse mit Userdaten zu füttern?

        Wie dem auch sein - das Script sollte natürlich so oder so sicher sein, allerdings dachte ich bis jetzt, dass es das ist. Jetzt könnte ich natürlich über die Datenbank- und Tabellennamen noch mal mysql_real_escape_string() drüber laufen lassen, jedoch sehe ich folgendes Problem darin:

        Angenommen magic_quotes ist aktiviert, dann müsste man auf $_POST bzw. $_GET Daten erst stripslashes() laufen lassen, weil es sonst ein doppeltes Escapen geben würde - allerdings kann ich im Script ja nicht feststellen, ob die Werte aus $_POST bzw. $_GET kommen oder ob sie von Hand eingegeben wurden - es könnte also sein, dass ich mit stripslashes() was entferne, was gar nicht durch magic_quotes dahin gekomme ist.

        Hm, ist das jetzt verständlich ausgedrückt gewesen? ;-)

        Weiterhin würde ein „wissender“ PHP Programmierer ja über die Daten selber noch mal mysql_real_escape_string() drüber laufen lassen, wozu es dann auch zu einem doppelten Escapen kommen würde.

        Und last but not least bin ich mir gar nicht sicher, ob man beim Datenbanknamen SQL Injections machen kann... Auch bei den Tabellennamen weiß ich nicht so genau - erst mal setze ich die Namen alle zwischen Backticks (`) und zweitens findet das Script selber ja die Tabellennamen herraus indem es sie sich von MySQL holt.

        Wie dem auch sein - ich habe die in Sachen Error Handling überarbeitete Version jetzt mal online gestellt.
        Ich würde mich freuen, wenn du sie dir nochmal anschaust.

        MfG, Dennis.

        1. echo $begrüßung;

          Die übergebenen Parameter für Datenbank- und Tabellennamen werden nicht maskiert, was man unter Umständen für SQL-Injection ausnutzen kann.

          Hm, eine ernste Sache, die du da ansprichst - erst mal vorweg, denkst du wirklich jemand könnte auf die Idee kommen, die Export Klasse mit Userdaten zu füttern?

          Dieses Argument habe ich kommen sehen :-) Es ist aber schlicht egal, an welcher Stelle du nicht damit rechnest, dass so etwas passieren könnte. Wenn es passiert, ist es zu spät und dein Argument, dass du niemals mit von außen manipulierten/manipulierbaren Daten rechnest ist dann auch kein Trost mehr. Es gibt ja auch noch den register_globals-Mechanismus, der ungefragt Variablen im Programm erzeugt. Gehe nicht davon aus, dass der Anwender deiner Klasse alles richtig macht.

          Wie dem auch sein - das Script sollte natürlich so oder so sicher sein, allerdings dachte ich bis jetzt, dass es das ist. Jetzt könnte ich natürlich über die Datenbank- und Tabellennamen noch mal mysql_real_escape_string() drüber laufen lassen, jedoch sehe ich folgendes Problem darin:

          Angenommen magic_quotes ist aktiviert, dann müsste man auf $_POST bzw. $_GET Daten erst stripslashes() laufen lassen, weil es sonst ein doppeltes Escapen geben würde - allerdings kann ich im Script ja nicht feststellen, ob die Werte aus $_POST bzw. $_GET kommen oder ob sie von Hand eingegeben wurden - es könnte also sein, dass ich mit stripslashes() was entferne, was gar nicht durch magic_quotes dahin gekomme ist.

          Gut erkannt. Es ist aber nicht deine Aufgabe für die Richtigkeit der übergebenen Parameter zu sorgen. Du hast sie nur unbeschadet ans Ziel zu bringen oder mit Fehlermeldungen um dich zu werfen, wenn das nicht geht. Man muss nicht alle Dummheiten der Anwender korrigieren wollen, man muss nur dafür sorgen, dass sie keinen Schaden anrichten.

          Weiterhin würde ein „wissender“ PHP Programmierer ja über die Daten selber noch mal mysql_real_escape_string() drüber laufen lassen, wozu es dann auch zu einem doppelten Escapen kommen würde.

          Das ist nicht seine Aufgabe. Er kann auch nicht wissen, in welcher Form du die übergebenen Werte verwendest. Vielleicht brauchst du sie an drei Stellen deiner Klasse einmal so, einmal so und dann noch einmal ganz anders. Es wäre kontraproduktiv, sie bereits nur für einen einzigen Anwendungsfall hin zu optimieren. Wenn er das doch tut, bekommt er von dir entweder nicht das gewünschte Ergebnis oder eine Fehlermeldung, und zwar weil die Datenbank diesen sonderzeichenbehafteten Tabellen-/Datenbank-Namen nicht finden konnte, nicht weil du ihn irgendwie analysiert hast.

          Ich predige ja auch gelegentlich, Demaskierungen ankommender Daten so früh wie möglich durchzuführen und abgehende Daten erst und nur zur Übergabe an das Zielmedium zu maskieren. Hin- und Hermaskierungen mitten in der Verarbeitung tragen nicht grade zur Übersichtlichkeit des Prozesses bei.

          Und last but not least bin ich mir gar nicht sicher, ob man beim Datenbanknamen SQL Injections machen kann...

          Alle Stellen zu denen unmaskierte Daten gelangen können sind anfällig. Aus deiner Sicht magst du alle (dir bekannten) Angriffsmöglichkeiten als nicht zielführend bewertet haben, und trotzdem hast du die eine Möglichkeit übersehen, bei der es passieren kann.

          Auch bei den Tabellennamen weiß ich nicht so genau - erst mal setze ich die Namen alle zwischen Backticks (`) und zweitens findet das Script selber ja die Tabellennamen herraus indem es sie sich von MySQL holt.

          Nun, man kann export_table_data() auch zu Fuß aufrufen. PHP4 sei Dank (oder auch nicht) sind ja alle Methoden public.

          Wie dem auch sein - ich habe die in Sachen Error Handling überarbeitete Version jetzt mal online gestellt.
          Ich würde mich freuen, wenn du sie dir nochmal anschaust.

          var $newline = "\n";
          Ich würde keine Klassenvariable dafür verwenden, zumal es außer einer Quelltextänderung keine Möglichkeit gibt, die zu verändern. Mein Vorschlag wäre eine Konstante zu definieren, falls sie noch nicht anderswo gesetzt wurde. So kann man vor dem Include deiner Klasse Einfluss darauf nehmen.
            if (!defined('NL'))
              define('NL, "\n");
          O.K. Der Anwender kann die Eigenschaft nach erfolgter Instantiierung ändern. Dazu muss er aber voraussetzen, dass sie bis dahin noch nicht verwendet wurde. (Die Analyse des Konstruktor-Quelltexts, um das herauszufinden, ist keine sehr feine Option.)
          Alternativ wäre auch noch ein weiter optionaler Konstruktor-Parameter denkbar.

          Die Zwischenvariable $con in Zeile 77 ff. ist nicht nötig. Du kannst gleich $this->con verwenden.

          Teilweise gibt es Ansätze, das Ergebnis variieren zu können (z.B. Parameter $drop_if_exists für Methode export_table_structure(), Zeile 126). Beim Aufruf der Methode (Zeile 251) wird dann aber ein fest vorgegebener Wert verwendet. Da gibt es also noch Erweiterungspotential für die Klasse. :-)

          false (Zeilen 138 und 157) ist kein wirklich geeigneter Wert, um einen String zu erweitern (Zeile 251f.) Außerdem sagt make_dump() in dem Fall, dass alles in Ordnung wäre. Nur das Ergebnis ist dann nicht wie vom Anwender erwartet ...

          (Mit sprintf() bekommst du Konstrukte wie in Zeile 196 ff. etwas lesbarer gestaltet.)

          Das sind nur Dinge, die mir beim Drüberschauen aufgefallen sind. Die Klasse einmal anzuwenden habe ich nicht versucht.

          echo "$verabschiedung $name";

          P.S. Sind meine obigen Aussagen - "Vertraue nicht den vom User übergebenen Daten" vs. "Vertraue dem was der User übergibt" - widersprüchlich? Das scheint mir auf den ersten Blick auch so. Es kommt darauf an, die richtige Haltung bei diesem Spagat zu finden; Absicherung des eigenen Programmteils, so dass Fehler keine negativen Auswirkungen haben, und "Anwenderbevormundung", indem man seine Parameter kritisiert, in ein optimales Verhältnis zu setzen.

          1. Hi dedlfix,

            Es ist aber schlicht egal, an welcher Stelle du nicht damit rechnest, dass so etwas passieren könnte. […]

            Ja, das sehe ich ein - deshalb auch mein anschließendes

            das Script sollte natürlich so oder so sicher sein

            Gut erkannt. Es ist aber nicht deine Aufgabe für die Richtigkeit der übergebenen Parameter zu sorgen. Du hast sie nur unbeschadet ans Ziel zu bringen oder mit Fehlermeldungen um dich zu werfen, wenn das nicht geht.

            Nehmen wir einmal an, es geht um folgenden String: foo " bar.

            Durch magic_quotes wurde da bereits ein Slashs vor das Anführungszeichen gesetzt, nun wende ich mysql_real_escape_string() an und daraus wird: foo \" bar - ich habe damit also soeben eine Sicherheitslücke geöffnet.

            An der Stelle frage ich mich eben, was besser ist - und muss sagen, dass ich keine Ahnung habe…

            Man muss nicht alle Dummheiten der Anwender korrigieren wollen, man muss nur dafür sorgen, dass sie keinen Schaden anrichten.

            …dieser Satz gefällt mir aber sehr gut ;-) Ich denke mal, dass ich dann einfach mysql_real_escape_sring() anwenden werde - es ist dann Sache des Users dafür zu sorgen, dass die Strings nicht bereits escaped sind.

            Hin- und Hermaskierungen mitten in der Verarbeitung tragen nicht grade zur Übersichtlichkeit des Prozesses bei.

            Dito.

            Alle Stellen zu denen unmaskierte Daten gelangen können sind anfällig. Aus deiner Sicht magst du alle (dir bekannten) Angriffsmöglichkeiten als nicht zielführend bewertet haben, und trotzdem hast du die eine Möglichkeit übersehen, bei der es passieren kann.

            Stimmt - aber da kommt noch eine Frage auf: ist mysql_real_escape_string() auch dafür gedacht, auf Tabellennamen angewendet zu werden? Ich habe es bis jetzt immer mehr dafür gehalten, es auf quotierte Strings anzuwenden.

            Bei einem Tabellennamen wäre ja wichtig, dass mysql_real_escape_string() auch die escaped, also zu \ macht - ich werde mal testen müssen, ob dem so ist - wenn dem nicht so ist, würde der String
              tabelle; DELETE FROM tabelle
            eingefügt in
              SELECT * FROM [code lang=php]$string{:.language-sql}[/code]
            immer noch zu
              SELECT * FROM tabelle; DELETE FROM tabelle``
            werden und damit Schaden anrichten.

            Nun, man kann export_table_data() auch zu Fuß aufrufen. PHP4 sei Dank (oder auch nicht) sind ja alle Methoden public.

            Eher „oder auch nicht“ - einer der Gründe, weshalb ich OOP in PHP4 nicht mag, wenn schon OOP, dann auch richtig.

            var $newline = "\n";
            Ich würde keine Klassenvariable dafür verwenden, zumal es außer einer Quelltextänderung keine Möglichkeit gibt, die zu verändern.

            Doch, dank PHP4 kannst du folgendes machen:

            $instanz = new MySQLDBExport();  
            $instanz->newline = "\r\n";
            

            Die Variable war eigentlich so gedacht, dass sie als public definiert werden sollte, aber… Du weißt schon ;-)

            Mein Vorschlag wäre eine Konstante zu definieren, falls sie noch nicht anderswo gesetzt wurde.

            Konstanten mag ich deshalb nicht so, weil diese „superglobal“ sind - also überall gelten - vielleicht möchte ja jemand nach mir im Script noch NEWLINE definieren.

            O.K. Der Anwender kann die Eigenschaft nach erfolgter Instantiierung ändern. Dazu muss er aber voraussetzen, dass sie bis dahin noch nicht verwendet wurde. (Die Analyse des Konstruktor-Quelltexts, um das herauszufinden, ist keine sehr feine Option.)

            Das verstehe ich nicht ganz - nach der Instantiierung lässt sich $newline ändern wie ich oben gezeigt habe, wolltest du das sagen? Dann verstehe ich aber den nachfolgenden Satz nicht…

            Alternativ wäre auch noch ein weiter optionaler Konstruktor-Parameter denkbar.

            Das ist die Methode, die mir am besten gefällt - oder eventuell noch eine weitere Funktion set_newline($newline).

            Die Zwischenvariable $con in Zeile 77 ff. ist nicht nötig. Du kannst gleich $this->con verwenden.

            Stimmt, danke.

            Teilweise gibt es Ansätze, das Ergebnis variieren zu können (z.B. Parameter $drop_if_exists für Methode export_table_structure(), Zeile 126). Beim Aufruf der Methode (Zeile 251) wird dann aber ein fest vorgegebener Wert verwendet. Da gibt es also noch Erweiterungspotential für die Klasse. :-)

            Ja, da hast du Recht ;-) Wobei ich es mir als ich damit angefangen habe eben so gedacht habe, dass es die Einzel-Funktionen gibt - wer alles selber festlegen will, soll diese Einzelfunktionen nutzen, make_dump() sollte dann ein Interface sein, dass auch mit DAU-Kenntnissen zu nutzen ist.

            false (Zeilen 138 und 157) ist kein wirklich geeigneter Wert, um einen String zu erweitern (Zeile 251f.) Außerdem sagt make_dump() in dem Fall, dass alles in Ordnung wäre. Nur das Ergebnis ist dann nicht wie vom Anwender erwartet ...

            Stimmt, auch da sollte man noch etwas dran arbeiten - vielleicht gibt das dann zusammen mit ein paar neuen Funktionen und Funktionsparametern eine ganz neue Klasse - Version 3.0 ;-)

            Das sind nur Dinge, die mir beim Drüberschauen aufgefallen sind. Die Klasse einmal anzuwenden habe ich nicht versucht.

            Ich danke dir auf jeden Fall sehr für das Drüberschauen - den eigenen Quellcode auf Fehler zu untersuchen ist finde ich stets schwerer bzw. darin Fehler zu finden ist schwerer als dies beim Quellcode von anderen Leuten zu tun.

            MfG, Dennis.

            1. echo $begrüßung;

              Nehmen wir einmal an, es geht um folgenden String: foo " bar.

              Durch magic_quotes wurde da bereits ein Slashs vor das Anführungszeichen gesetzt, nun wende ich mysql_real_escape_string() an und daraus wird: foo \" bar - ich habe damit also soeben eine Sicherheitslücke geöffnet.

              Nein. Du hast übersehen, dass mysql_real_escape_string() sich neben dem " auch um den \ kümmert. Es kommt also foo \" bar raus.

              ist mysql_real_escape_string() auch dafür gedacht, auf Tabellennamen angewendet zu werden? Ich habe es bis jetzt immer mehr dafür gehalten, es auf quotierte Strings anzuwenden.

              Es sieht mir auch so aus, als ob mysql_real_escape_string() nur für Werte und nicht für Identifier gedacht ist. Nach Lekture des Handbuchkapitels Database, Table, Index, Column, and Alias Names möchte ich meinen, dass es sogar ungeeignet ist. Dort steht auch, welche Zeichen nicht erlaubt sind und dass ein Backtick zu verdoppeln ist, wenn es Bestandteil eines in Backticks eingeschlossenen Bezeichners ist. Du müsstest also am Besten eine eigene Bezeichner-Quotier-Funktion/-Methode schreiben, die das alles berücksichtigt.

              [...] würde der String
                tabelle; DELETE FROM tabelle
              eingefügt in
                SELECT * FROM $string
              immer noch zu
                SELECT * FROM tabelle; DELETE FROM tabelle
              werden und damit Schaden anrichten.

              Bleib mal bei realistischen Beispielen! :-) Solche Mehrfachstatements werden von MySQL im Normalfall abgelehnt (MySQL-API-Beschreibung zu mysql_query()). Man muss sich schon etwas mehr bemühen, wenn man dieses Feature haben möchte: C API Handling of Multiple Query Execution. Für PHP braucht man dazu die MySQL Improved Extension (mysqli) und mysqli_multi_query() (siehe auch mysqli_real_connect() (bei der Beschreibung der Flags)).
              Trotzdem bleibt die Möglichkeit, das eine erlaubte Statement so zu verändern, dass es ein anderes Ergebnis liefert als das vom Programmierer vorgesehene. Das reicht möglicherweise schon aus, um an Informationen zu kommen, die nicht für aller Leute Augen bestimmt waren.

              [...] PHP4 sei Dank (oder auch nicht) sind ja alle Methoden public.

              var $newline = "\n";
              Ich würde keine Klassenvariable dafür verwenden, zumal es außer einer Quelltextänderung keine Möglichkeit gibt, die zu verändern.
              Doch, dank PHP4 kannst du folgendes machen:
              $instanz->newline = "\r\n";[/code]

              Hier hatte ich anscheinend schon wieder verdrängt, dass ja bei PHP4 alles public ist und "ordentliches OOP" im Kopf gehabt.

              O.K. Der Anwender kann die Eigenschaft nach erfolgter Instantiierung ändern.

              Das fiel mir dann aber doch noch auf, weswegen ich hier einlenkte ...

              Dazu muss er aber voraussetzen, dass sie bis dahin noch nicht verwendet wurde. (Die Analyse des Konstruktor-Quelltexts, um das herauszufinden, ist keine sehr feine Option.)

              ... um noch ein Härchen in der Suppe zu finden. :-)

              echo "$verabschiedung $name";

              1. Hi dedlfix,

                Du bist fleißig gewesen - dein Posting ist schon total Self-Farben[1] ;-)

                [1] …vor lauter Links :-)

                Nein. Du hast übersehen, dass mysql_real_escape_string() sich neben dem " auch um den \ kümmert. Es kommt also foo \" bar raus.

                Oh, stimmt, du hast Recht.

                ist mysql_real_escape_string() auch dafür gedacht, auf Tabellennamen angewendet zu werden? Ich habe es bis jetzt immer mehr dafür gehalten, es auf quotierte Strings anzuwenden.

                Es sieht mir auch so aus, als ob mysql_real_escape_string() nur für Werte und nicht für Identifier gedacht ist. Nach Lekture des Handbuchkapitels Database, Table, Index, Column, and Alias Names möchte ich meinen, dass es sogar ungeeignet ist. Dort steht auch, welche Zeichen nicht erlaubt sind und dass ein Backtick zu verdoppeln ist, wenn es Bestandteil eines in Backticks eingeschlossenen Bezeichners ist. Du müsstest also am Besten eine eigene Bezeichner-Quotier-Funktion/-Methode schreiben, die das alles berücksichtigt.

                Gut, das entspräche ja schon mal dem, was ich mir gedacht habe - dass mysql_real_escape_string() hier nicht weiterhilft.

                Doch denken wir mal konkret - ich zitiere noch mal einen Satz aus der von dir verlinkten Manual-Seite:
                „If the character to be included within the identifier is the same as that used to quote the identifier itself, then you need to double the character.“

                Das heißt, wir müssten im Tabellen- bzw. Datenbanknamen einfach nur alle ` durch `` ersetzen, damit wären sie entschärft. Ich behaupt jetzt auch mal noch, das man sonst kein weiteres Escaping betreiben muss, mal schauen:

                Folgender SQL Code sei gegeben:
                  SELECT * FROM $string

                Für $string wird folgendes escaped (wie oben beschreiben) und danach eingesetzt:
                  tabelle` WHERE foo = "bar"

                Dabei käme herraus:
                  SELECT * FROM tabelle`` WHERE foo="bar"

                Dann sollte tabelle`` WHERE foo="bar" als Tabellennamen verwendet werden - das das keinen Slash, Backslash oder Punkt enthält, sollte das nach dem Manual ein gültiger Tabellenamen sein, allerdings wird die Tabelle nicht existieren ;-)

                Bleib mal bei realistischen Beispielen! :-) Solche Mehrfachstatements werden von MySQL im Normalfall abgelehnt [...] Trotzdem bleibt die Möglichkeit, das eine erlaubte Statement so zu verändern, dass es ein anderes Ergebnis liefert als das vom Programmierer vorgesehene. Das reicht möglicherweise schon aus, um an Informationen zu kommen, die nicht für aller Leute Augen bestimmt waren.

                Welche Möglichkeiten gäbe es noch? Ich habe oben jetzt noch eine WHERE Klausel angehängt, das wäre eigene Möglicheit, aber an mehr Informationen kommt man damit im Normalfall auch nicht, eher nur an weniger *g* Wobei mir gerade einfällt: Damit könnte es z.B. möglich sein, einen User-Account anzulegen (erneut), der bereits existiert und damit ein System rauszubringen - OK.

                Doch was ließe sich noch machen, wenn wir uns auf ein SQL-Statement beschränken wollen? Eventuell noch so ORDER BY Geschichten und so, wäre natürlich böse, wenn das möglich wäre, aber ich wüsste nicht, wofür sich das ausnutzen ließe.

                Dazu muss er aber voraussetzen, dass sie bis dahin noch nicht verwendet wurde. (Die Analyse des Konstruktor-Quelltexts, um das herauszufinden, ist keine sehr feine Option.)

                Du meinst mit „sie“ die Klassenvariable? Von wem soll die benutzt worden sein? Gut, man muss sie natürlich setzen, bevor die Klasse selber sie verwendet.

                MfG, Dennis.

                1. echo $begrüßung;

                  Bleib mal bei realistischen Beispielen! :-) Solche Mehrfachstatements werden von MySQL im Normalfall abgelehnt [...] Trotzdem bleibt die Möglichkeit, das eine erlaubte Statement so zu verändern, dass es ein anderes Ergebnis liefert als das vom Programmierer vorgesehene. Das reicht möglicherweise schon aus, um an Informationen zu kommen, die nicht für aller Leute Augen bestimmt waren.

                  Welche Möglichkeiten gäbe es noch?

                  Wenn man eine Tabellennamen-Lücke ausnutzen will, könnte man vielleicht was mit Joins machen. Es kommt ja immer noch auf das konkrete SQL-Statement an, das man zu manipulieren gedenkt. Wenn in der SELECT-Klausel Spaltennamen statt * stehen, nützt das kartesische Produkt eines Joins auch nicht viel, um an die Informationen der anderen Tabelle zu kommen. Doch in deinem Fall steht das für den Backup-Zweck doch nicht ganz unsinnige * in der SELECT-Klausel ...
                  Ich kann mir durchaus einen Anwendungsfall vorstellen: Jemand soll "seine" Tabelle backupen dürfen, andere aber nicht. Der Programmierer war zu faul oder unfähig ein gescheites Zugriffskonzept zu verwenden und nimmt eine DB-Userkennung für alles, ...
                  Ob das jetzt ein realistisches Beispiel war? Wer weiß. Es soll schon vorgekommen sein, dass ein Pferd seinen Mageninhalt vor der Apotheke liegen sah. :-)

                  Ich habe oben jetzt noch eine WHERE Klausel angehängt, das wäre eigene Möglicheit, aber an mehr Informationen kommt man damit im Normalfall auch nicht, eher nur an weniger *g*

                  Wenn man SQL-Injection allgemein betrachtet und eine WHERE-Klausel-Lücke ausnutzt, könnte man grade solch eine vom Programmierer vorgesehene Einschränkung aufheben. Das Anhängen von "OR 1" ergibt eine uneingeschränkte Ergebnismenge.

                  echo "$verabschiedung $name";

                  1. Hi dedlfix,

                    Wenn man eine Tabellennamen-Lücke ausnutzen will, könnte man vielleicht was mit Joins machen.

                    An die Möglichkeit habe ich jetzt so spontan gar nicht mehr gedacht - da ließe sich vielleicht noch was machen.

                    Ich kann mir durchaus einen Anwendungsfall vorstellen: Jemand soll "seine" Tabelle backupen dürfen, andere aber nicht. Der Programmierer war zu faul oder unfähig ein gescheites Zugriffskonzept zu verwenden und nimmt eine DB-Userkennung für alles, ...

                    Ist vielleicht ansatzweise realistisch - wobei man schon verdammt blöd sein müsste, wenn man den Leuten die Möglichkeit gibt, den Benutzernamen frei zu wählen, der sollte in so einem Fall eigenltich aus einer Session oder aus einer Datenbank kommen.

                    Wenn man SQL-Injection allgemein betrachtet und eine WHERE-Klausel-Lücke ausnutzt, könnte man grade solch eine vom Programmierer vorgesehene Einschränkung aufheben. Das Anhängen von "OR 1" ergibt eine uneingeschränkte Ergebnismenge.

                    Dazu  müsste allerdings die Einfügeposition der Daten _hinter_ dem WHERE liegen - was bei Tabellen recht unwahrscheinlich ist ;-) Ok, da kommen jetzt wieder JOIN's ins Spiel.

                    Wie auch immer - ich habe jetzt die neue, überarbeitete Version der MySQLDBExport.class.php online gestellt, Version 2.0.1 (Download).

                    Darin habe ich neben dem escape_table_name() noch eine Funktion set_newline() und get_error() eingebaut. Weiterhin gibt es bei make_dump() jetzt die Möglichkeit Parameter für DROP IF EXISTS und auszulassende Felder an die export_table_* Funktionen durchzuschleusen.

                    Ich möchte mich noch mals herzlich bei dir für deine Mühe und dein Engagement bedanken und hoffe, dass die Klasse jetzt soweit „bugfrei“ ist - als nächstes würde dann wohl noch anstehen, die Klasse für PHP5 zu überarbeiten.

                    MfG, Dennis.

                    1. echo $begrüßung;

                      Ich [...] hoffe, dass die Klasse jetzt soweit „bugfrei“ ist

                      Aufgefallen ist mir noch, dass in Zeile 208 ein $this->escape_table_name() kommen sollte. (Und $fields/$field/Field statt $keys/$key/Key fände ich auch passender.)((Und der phpMyAdmin (2.7.0) kann auch nicht richtig mit Backticks in Feldnamen umgehen.))

                      echo "$verabschiedung $name";

                      1. Hi dedlfix,

                        Aufgefallen ist mir noch, dass in Zeile 208 ein $this->escape_table_name() kommen sollte.

                        Ok, ist erledigt.

                        Und der phpMyAdmin (2.7.0) kann auch nicht richtig mit Backticks in Feldnamen umgehen.

                        Hm, das ist wohl noch mal ein anderes Thema, mit dem es sich auseinander zu setzen gilt.

                        MfG, Dennis.

  2. echo $begrüßung;

    Wie kriege ich einen Dump des Inhalts hin?? Ich möchte gern, daß mir der Inhalt Zeile für Zeile so präsentiert wird:
    INSERT tabellenname SET (Wert1,Wert2,...Wertn);

    Natürlich könnte ich das mit "Select * FROM ..." hinkriegen indem ich die Feldinhalte zum gesuchten String zusammenbaue, aber dabei sehe ich mindesten 2 Probleme. 1. muß ich rauskriegen, welches Feld eine Zeichenkette ist, damit ich den Feldinhalt in "'" setzen kann.

    mysql_field_type() liefert diese Information. Und da du * selektierst wirst du auch noch den Spaltennamen mit mysql_field_name() abfragen wollen.

    2 müssen ja bestimmte Zeichen in der "Insert"-Anweisung konvertiert werden, ein Zeilenumbruch wird z.B. zu "\n" usw., wobei hier ja die Gefahr besteht, daß man Zeichen vergißt, wenn man das per selbstgestricktem Programm erledigt.

    Wie machst du es denn bei Usereingaben? Du verlässt dich doch da hoffentlich nicht auf die unsicheren Magic Quotes? (Unsicher in dem Sinne, dass sie ausgeschaltet sein können und auch nicht alle zu maskierenden Zeichen berücksichtigen.) mysql_real_escape_string() ist für beide Probleme besser geeignet.

    echo "$verabschiedung $name";