Wichtige Sicherheitsfrage: SQL Injection

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Wichtige Sicherheitsfrage: SQL Injection

    Meine Frage:
    Wenn folgender Code am Anfang der Datei includiert wird,
    müssen später die globalen Variablen nicht mehr ecaped werden?
    Code:

    Quellcode

    1. if(get_magic_quotes_gpc() == 0) {
    2. foreach($_GET as $key => $value) { $_GET[$key] = htmlspecialchars(trim(addslashes($value)), ENT_QUOTES, 'UTF-8'); }
    3. foreach($_POST as $key => $value) { $_POST[$key] = htmlspecialchars(trim(addslashes($value)), ENT_QUOTES, 'UTF-8'); }
    4. foreach($_SERVER as $key => $value) { $_SERVER[$key] = htmlspecialchars(addslashes($value), ENT_QUOTES, 'UTF-8'); }
    5. foreach($_COOKIE as $key => $value) { $_COOKIE[$key] = htmlspecialchars(trim(addslashes($value)), ENT_QUOTES, 'UTF-8'); }
    6. foreach($_SESSION as $key => $value) { $_SESSION[$key] = htmlspecialchars(trim(addslashes($value)), ENT_QUOTES, 'UTF-8'); }
    7. }
    8. set_magic_quotes_runtime(0);

    Kann man dann solche SQL-Anfragen verwenden?

    Quellcode

    1. SELECT memberid FROM members WHERE membername = $_POST['name']
  • Hi.
    Generell würde ich immer die Funktionen des Datenbankwrappers vorziehen. Sei es PDO, MySQLi oder die alte mysql_*** Schnittstelle.
    Was du nicht abdeckst sind Mehrdimensionale Arrays. Wie du sie zum Beispiel bei Multiselects oder Checkboxen hast. Außerdem müssen Zahlen ohne Hochkommas getrennt behandelt werden.

    Vollständiger Hack:

    Quellcode

    1. <?php
    2. $_POST['size'] = "1,text=(SELECT password FROM members WHERE membername=admin) ";
    3. foreach($_GET as $key => $value) { $_GET[$key] = htmlspecialchars(trim(addslashes($value)), ENT_QUOTES, 'UTF-8'); }
    4. foreach($_POST as $key => $value) { $_POST[$key] = htmlspecialchars(trim(addslashes($value)), ENT_QUOTES, 'UTF-8'); }
    5. foreach($_SERVER as $key => $value) { $_SERVER[$key] = htmlspecialchars(addslashes($value), ENT_QUOTES, 'UTF-8'); }
    6. foreach($_COOKIE as $key => $value) { $_COOKIE[$key] = htmlspecialchars(trim(addslashes($value)), ENT_QUOTES, 'UTF-8'); }
    7. echo "UPDATE members SET size = {$_POST[size]} WHERE memberid=5";
    8. //output: UPDATE members SET size = 1,text=(SELECT password FROM members WHERE memberid=1) WHERE memberid=5
    9. ?>
    Alles anzeigen
  • d0nut schrieb:

    Was du nicht abdeckst sind Mehrdimensionale Arrays. Wie du sie zum Beispiel bei Multiselects oder Checkboxen hast. Außerdem müssen Zahlen ohne Hochkommas getrennt behandelt werden.

    OK, aber momentan sind keine davon in Gebrauch und wenn doch dann werde ich den Code entsprechend ändern! :)
    Wenn ich per str_replace noch ein paar "Badwords" filtere wie z.B. SELECT, FROM, WHERE usw. (die mit null ersetze) wäre es dann sicher?

    PS: Danke schonmal für die schnelle Hilfe, scheint ein tolles Board zu sein! :D

    E:

    Quellcode

    1. set_magic_quotes_runtime(0);

    Sollte entfernt werden oder? Weil das würde das escapen deaktiveren.
    Also entweder entfernen oder vor die foreach-Schleifen setzen?
  • Generell ist ein blacklistverfahren nie sicher.

    Was ich dir empfehlen kann ist der HTML Purifier:
    htmlpurifier.org/

    Ich bin ja so ein kleiner Buch fetischist und kann dir auf jedenfall das Buch empfehlen.
    Da bekommt man einen sehr guten Einblick über XSS, SQL Injection, CSRF ... etc. ...
    [amazon]3898645355[/amazon]

    Leider sind nur meines erachtens 200Seiten des Buches brauchbar, aber die sind ihr Geld wert
  • naja, das Problem sind nicht die Badwords sondern die leichtsinnige Verwendung von Zahlenfeldern.
    Hier sollte man typsicherheit garantieren.

    Anderes Beispiel:

    Quellcode

    1. $_POST['memberid'] = "500 OR memberid > 0";
    2. echo "UPDATE members SET password = md5('meinpasswort') WHERE memberid=".$_POST['memberid'];
    3. //output: UPDATE members SET password = md5('meinpasswort') WHERE memberid=500 OR memberid > 0


    Das Beispiel ist zugegeben unrealistisch... Aber jeder macht mal Fehler.
    Die richtige Lösung wäre hier:

    Quellcode

    1. echo "UPDATE members SET password = md5('meinpasswort') WHERE memberid=".intval($_POST['memberid']);


    Aber wie gesagt: Wenn du einen "richtigen" Datenbankwrapper verwendest, ersparst du dir viel Mühe und Ärger.
    Hier unsere [wiki]Einführung in PDO[/wiki]

    Anderes Beispiel:

    Quellcode

    1. $_POST['size'] = "1,admin=1 ";
    2. echo "UPDATE members SET size = {$_POST[size]} WHERE memberid=5";
    3. //output: UPDATE members SET size = 1,admin=1 WHERE memberid=5
  • Das mit intval ist mir bekannt :D
    aber das sollte eher nur ein Beispiel sein,
    es kommen eher Strings/Texte darin vor.
    Und wie sieht es aus wenn ich jeden Query in meiner Datenbank-Klasse
    vorher mit mysql_real_escape_string escape?

    E:
    Funktion zum Verarbeiten aller Arraywerte:

    Quellcode

    1. function addslashes_deep($value)
    2. {
    3. $value = is_array($value) ?
    4. array_map('addslashes_deep', $value) :
    5. addslashes($value);
    6. return $value;
    7. }
    8. Also z.B.:
    9. foreach($_POST as $key => $value) { $_POST[$key] = htmlspecialchars(trim(addslashes_deep($value)), ENT_QUOTES, 'UTF-8'); }
    Alles anzeigen

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von PHP-Fortg ()

  • Deine Konstruktion ist zwar sehr schön, aber pass auf, dass du dir nicht jegleiche Strings mit den slashes "zerstörst".

    Hast du das schonmal ausprobiert? Alles was du da quotest übernimmt MySQL afaik mit in die Datenbank.

    Nehmen wir an du hast ein String:

    Quellcode

    1. $str = "Peter's";

    Jetzt Quotest du:

    Quellcode

    1. echo $str; // Ausgabe Peter\'s

    Und so stehts dann auch in der Datenbank.

    Wenn du pech hast und das ganze summiert sich, dann sieht dein String bei mehrfachen einlesen, speichern, auslesen so aus:
    Peter\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'s
    Und wenn du dann noch ein "TEXT"-Feld hast, dann summiert sich das ganze natürlich gegen unendlich und du Müllst die gesamte Datenbank voll.
    Aus der oberen Ausgabe wird dann :
    Peter\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'s
    und beim nächsten mal:
    Peter\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'s
    usw. ...

    Ich habe das selber mal bei einem selbst geschriebenen CMS mit einem WYSIWYG-Editor miterlebt, der dann logischerweise nicht die slashes angezeigt hatte.
    Nach circa einem Jahr fand es die Datenbank überhaupt nicht mehr Lustig, dass sich tausende Texte immer wieder und wieder multipliziert hatten :D



    Dann solltest du wie geschrieben PDO oder mysqli_ nutzen.
    Dort gibt es prepared Statements.

    de3.php.net/manual/de/mysqli.prepare.php

    Quellcode

    1. $city = "Amersfoort";
    2. /* create a prepared statement */
    3. if ($stmt = mysqli_prepare($link, "SELECT District FROM City WHERE Name=?")) {
    4. /* bind parameters for markers */
    5. mysqli_stmt_bind_param($stmt, "s", $city);
    6. /* execute query */
    7. mysqli_stmt_execute($stmt);
    8. ....
    Alles anzeigen


    Damit trennst du das reine SQL Statement und die Paramter. Beim binden übergibst du dann die Parameter und es wird dann automatisch von der Datenbank gequotet.

    Und wie du hier sehen kannst:
    de3.php.net/manual/de/mysqli-stmt.bind-param.php

    gibt es beim binden auch die Möglichkeit gleich einen Datentyp anzugeben.
    types: A string that contains one or more characters which specify the types for the corresponding bind variables:


    Damit sparst du dir dann auch das intval oder anders typecasting.


    Zum AUsgangspost zurück zu kommen, ist es so wie du selber sagst, dass man niemals 100%ig sicher ist, aber beruhigter kannst du auf jedenfall sein.
    Zu beachten gibt es ne Menge, vielleicht nicht mehr so viel in Bezug auf SQL Injection, aber es gibt ganz viele andere "tolle" Verfahren die man noch nutzen kann.


    de.wikipedia.org/wiki/Cross-Site_Scripting
    (wbb-security.de/support/progra…86-parametermanipulation/)
    de.wikipedia.org/wiki/Cross-Site_Request_Forgery

    Und unterschätz das nicht, es gibt genug Kiddy "Schritt-für-Schritt"-Anleitungen und Tools wo das jeder machen kann.


    Wie mehrmals geschrieben, wenn du das Geld entbehren kannst dann hol dir das oder ein vergleichbares Buch :)