de.comp.lang.php FAQ

16.18. Wie kann ich bösartigen Code in SQL-Abfragen unterbinden?

Keywords: SQL | Injection | Quoting

Antwort von Alex Kiesel

In nahezu allen Einsatzgebieten einer Datenbank wird die Datenbank durch ein bestimmtes Benutzerinterface (z.B. über das Web) abgefragt und auch gefüllt. Oft darf ein bestimmter Benutzer nicht alles sehen, was sich in der Datenbank befindet - und schon gar nicht ändern oder löschen. Falsch programmierte Scripte ermöglichen jedoch genau dies - dabei ist ein Schutz gegen die als SQL-Injection bekannte Technik gar nicht so schwer. Auf die Prüfung der übergebenen Parameter kommt es an. (Siehe dazu auch Prüfe importierte Parameter. Traue niemandem).

Zunächst mal ein Beispiel, wie eine solche SQL-Injektion aussehen könnte: in einer Benutzerverwaltung darf ein User genau sein eigenes Passwort ändern. Wir haben also die Tabelle "account", die insbesondere die Logindaten des Users und des Admins enthält. Der Benutzer sendet das Passwort-Ändern-Formular in seinem Browser ab und serverseitig wird das neue Passwort in die Datenbank geschrieben:

  $result= $db->update ('
    update account
    set password= "'.$_REQUEST['newpassword'].'"
    where username= "'.$_REQUEST['username'].'"'
  );

Hier wird die Variable $_REQUEST['newpassword'] nicht geprüft - der Benutzer kann eintragen, was er möchte. Mit etwas Trial-and-Error findet der Benutzer heraus, dass er die doppelten Anführungszeichen (") als String-Delimiter benutzen muss; er gibt nun ein Passwort seiner Wahl und als Username userxy" or username="admin. Somit ergibt sich nach der Textersetzung folgendes SQL:

  update account
  set password= "adminsuxx"
  where username="userxy" or username="admin"

Es kommt hier also hochgradig darauf an, niemals fremden Parametern zu trauen. Auf was muss also getestet werden? Parameter, die innerhalb von Quotes als String an die Datenbank übergeben werden sollen, dürfen selbst keine ungeschützten Quotes enthalten. Parameter, die IDs oder Zahlen repräsentieren, dürfen nur Ziffern enthalten. Die beiden Funktionen sichern genau dies, und sorgen zudem dafür, dass NULL-Values korrekt wiedergegeben werden:

  function sqlSafeString($param) {
    // Hier wird wg. der grossen Verbreitung auf MySQL eingegangen
    return (NULL === $param ? "NULL" : '"'.mysql_escape_string ($param).'"');
  }

  function sqlSafeInt($param) {
    return (NULL === $param ? "NULL" : intVal ($param));
  }

(Die genauen Vorgaben zum Schützen von Sonderzeichen hängen vom SQL-Dialekt des RDBMS ab und müssen gegebenenfalls angepasst werden.) Man hätte so oben beschriebenes SQL so umschreiben können:

  $result= $db->update ('
    update account
    set password= '.sqlSafeString ($_REQUEST['newpassword']).'
    where username= '.sqlSafeString ($_REQUEST['username'])
  );

Obiger SQL-Injection-Versuch wäre dann gescheitert (weil keine Zeile auf diesen Usernamen matcht):

  update account
  set password= "adminsuxx"
  where username="userxy\" or username=\"admin\""

Eine Funktion, die komfortable SQL-Manipulation mit automatischem Escaping bietet, wird in String-Quoting bei Sybase vorgestellt; sie ist zwar für Sybase geschrieben worden, lässt sich aber leicht für andere Datenbanksysteme adaptieren.

Weitere Informationen zu SQL-Injections und eine Übersicht über die spezifischen Anfälligkeiten verschiedener Datenbankmanagementsysteme findet sich unter SQL-Input Validation.

hosted by
schlund + partner

Valid HTML 4.01! Valid CSS!

16.18. Wie kann ich bösartigen Code in SQL-Abfragen unterbinden?
http://www.dclp-faq.de/q/q-sql-injection.html
de.comp.lang.php FAQ | (c) Copyright 2000-2003 Das dclp-FAQ-Team