dedlfix: Eintrag in Datenbank klappt nicht

Beitrag lesen

echo $begrüßung;

VALUES ($_POST[url], ......)";

Why is $foo[bar] wrong?

Wenn man Array-Werte in mit "" eingefassten Strings unterbringen möchte, muss man {}-Klammern verwenden. $string = "Ein Text mit einer {$array['variablen']} drin.";
Allgemein ist dieses Vorgehen, Benutzereingaben direkt in SQL-Stements unterzubringen, jedoch nicht anzuraten. (Fortsetzung dieses Themas weiter unten)

ini_set('error_reporting', E_ALL);

Um das error_reporting zu setzen kann man auch die eigens dafür existierende Funktion error_reporting() verwenden.

Damit siehst du Fehler, kannst du später wieder entfernen.

Konkreter: Mit der Voreinstellung des error_reporting-Wertes werden E_NOTICE-Meldungen nicht ausgegeben. Eine solche wird erzeugt, wenn man auf nicht vorhandene Variablen lesend zugreifen möchte. Sehr nützlich bei Tippfehlern in Variablennamen, und eben auch in diesem Fall, wenn man auf Variablen zugreift, die nicht angelegt wurden, weil register_globals ausgeschaltet war.

$eintrag = "INSERT INTO links (url, urlname, name, banner, beschreibung)
VALUES ('$url', '$urlname', '$name', '$banner', '$beschreibung')";

Ungeprüfte Benutzereingaben direkt in SQL-Statements einzubinden ist eine potentielle Sicherheitslücke und kann auch bei "gutmütigen Daten" zu Fehlern führen. Nehmen wir mal an, jemand hat als Name O'Conner eingegeben. Wie sieht dann der Wert von $eintrag aus?

INSERT INTO links (...) VALUES ('eine url', ..., 'O'Conner', ...)

Das ist fehlerhaft, weil --------------------------^ da der vor dem O begonnene String aufhört. Kritischer ist es, wenn man bei Authentifizierungsabfragen ebenso lasch behandelt. Da kann dann schon mal bei weniger gutmütigen Daten sowas bei rauskommen

SELECT felder FROM users WHERE name='irgendwas' OR '1' AND password='irgendwas';

Als Name wurde  irgendwas' OR '1  eingegeben. Durch das Nichtentschärfen der ' wird hier der der Befehl um ein OR '1' erweitert, was die WHERE-Bedingung immer true werden lässt. Als Ergebnis erhält man dann alle Datensätze statt nur einem oder keinem. Meist prüft der Anfänger dann auch nur ob entweder keiner existiert (z.B. wegen falschen Passworts) oder greift blind auf den ersten Satz des Ergebnisses zurück. Der Angreifer erwischt mit Glück den Admin-Account, denn der ist oftmals der zuerst eingetragene.

Es gibt ein PHP-Feature namens Magic Quotes, das diese SQL-Injection unterbinden soll, indem es einigen Zeichen ein \ voranstellt. Doch dieses Feature ist zu allgemein gehalten. Es entschärft zu wenig Zeichen, und manchmal benötigt man es gar nicht, weil die Daten einem anderen Medium mit anderen Maskierungsvorschriften übergeben werden sollen. (Zudem wird dieser Automatismus ab PHP6 nicht mehr vorhanden sein.)

Doch wie macht man es nun besser? Man verwende die für das jeweilige Ausgabemedium passende Maskierung. Die MySQL-API stellt dafür die Funktion mysql_real_escape_string() zur Verfügung. Zusammen mit sprintf() sieht ein übersichtliches INSERT-Statement beispielsweise so aus:

$eintrag = sprintf("INSERT INTO links (url, urlname, name, banner,beschreibung) " .  
    "VALUES ('%s', '%s', '%s', '%s', '%s')",  
  mysql_real_escape_string($_POST['$url']),  
  mysql_real_escape_string($_POST['$urlname']),  
  mysql_real_escape_string($_POST['$name']),  
  mysql_real_escape_string($_POST['$banner']),  
  mysql_real_escape_string($_POST['$beschreibung']));

Sollte Magic Quotes eingeschaltet sein, muss man es nun auschalten oder dessen Auswirkungen (am Scriptanfang) rückgängig machen: Disabling Magic Quotes.

echo "$verabschiedung $name";