Hi!
Ich vermisse ein Beispiel zu Prepared Statements.
Ich wollte die Prepared-Statements-Thematik nicht zu sehr ausbauen. Damit und mit den Eigenheiten und Unterschieden zwischen mysqli und PDO kann man gut einen eigenen Artikel füllen.
Ich vermisse die Aussage, dass man bei zusammengeklebten Statements sich sehr leicht SQL Injections einfängt, wenn man versehentlich nicht die richtige Quoting-Funktion benutzt (von denen es in PHP wohl einen ganzen Haufen gibt) oder den Funktionsaufruf rund um jeden einzelnen Parameter bei auch nur einem Parameter vergißt.
Egal, welche der in Frage kommenden Funktionen (mysql_escape_string, mysql(i)_real_escape_string und auch addslashes) man verwendet, die kritischen Zeichen sind damit abgedeckt. Der Unterschied zwischen addslashes und mysql_(real_)escape_string ist eher kosmetischer Natur - siehe den geklammerten Satz "Strictly speaking ...".
Es gibt ein Problem mit hierzulande nicht üblichen Mehrbytekodierungen. Wenn da die MySQL-Client-API nicht auf korrektem Weg die Kodierung mitgeteilt bekommen hat, maskiert sie falsch. Mit ISO-8859-x und UTF-8 ist das Problem jedoch nicht existent.
Ich vermisse die Aussage, dass bei Prepared Statements das Quoting-Problem wegfällt und damit das Risiko der SQL-Injection wegfällt.
Ein Beispiel für SQL-Injection fehlt ebenfalls.
Ist beides drin. Das Problem beim Kontextwechsel ist nicht primär der Sicherheitsaspekt. Deswegen reite ich auch nicht zu sehr auf dieser "Dramatik" rum.
Der ganze Absatz rund um die Prepared Statements kann leicht so gelesen werden, dass Prepared Statements eigentlich eine unnütze Erfindung sind, die man besser durch die altbewährte Cargo-Cult-Programmierung ersetzt.
Es ist Mehraufwand, der sich nicht in jedem Fall lohnt. Erheblich wird der Mehraufwand unter mysqli, wenn das Statement auch noch erst zur Laufzeit zusammengebaut werden soll. Der Wiederverwendbarkeitsvorteil ist damit auch aus dem Rennen.
Selbst wenn PHP für jeden Request eine neue DB-Connection öffnet, kann die DB selbst die Prepared Statements unabhängig von der Connection cachen und sich das tausendfache Neuparsen des selben Statements verkneifen -- und wenn nicht die DB, dann ein dazwischen geschaltetes Stückchen Software, z.B. zum Connection Pooling.
Wie soll das gehen? Nach dem Prepare bekommt man ein Handle auf das PS. Mit diesem Handle bindet und executiert man. Das Handle wird spätestens am Requestende entsorgt. Ich wüsste nicht (alles kann ich auch nicht wissen), dass da bei MySQL (andere DBMS kenne ich nicht intensiv genug) noch ein Statement-Cache existiert, der mir dann das "alte" Handle wieder besorgt. Der normale Query-Cache jedenfalls vergleicht die SQL-Statements erst nach der Platzhalter-Ersetzung. Alles andere wäre ja auch nicht sinnvoll, weil das Ergebnis ja von diesen Werten abhängig ist.
Prepared Statements sind sinnvoll, wenn man mehrere Datensätze schreiben will: prepare, execute for each record, finish. Sie sind auch sinnvoll, wenn man mehrere, bis auf die Parameter identische Abfragen laufen lassen will.
Ja, das schrieb ich, dass das ihre eigentliche Intention ist. Wer dafür Bedarf hat, kann sie ruhig einsetzen. Die Intention des Artikels ist jedoch Kontextwechsel und nicht Performance. Schon deshalb will ich nicht zu sehr in Details der PS gehen.
Ich sehe nur PHP und MySQL. Zugegeben, das ist die Standard-Lösung aller Billig- und Massenhoster. Aber es gibt noch andere Datenbanken (wie müßte da die entsprechende Quote-Funktion heißen?) und es gibt noch andere Programmiersprachen für die Serverseite (Perl, Ruby, Java, ...), die exakt die selben Kontextwechsel-Probleme haben.
Wer für das Thema erst einmal sensibilisiert ist, wird sich die entsprechenden Funktionen in anderen Systemen raussuchen können, finde ich. Da ich nicht mit allen DBMS-Schnittstellen Erfahrung habe, möchte ich dazu auch nichts sagen. Manche sind auch zu exotisch. Der Artikel sollte auch nicht zu voll werden.
Lo!