Moin!
Du sparst dir eventuell 0,1% CPU-Aufwand, du gewinnst aber mindestens 100% Gehirnkapazität für die übrigen Programmieraufgaben. Und verhindert 100% der durch Option 2 möglichen Programmierfehler.
Die Frage ist für mich, was sinnvoller ist. Ich denke, man sollte stets alle Eingaben überprüfen.
Das Überprüfen des Inhalts von Benutzerdaten auf Einhaltung einer gewissen Form ist nicht falsch, hat nur nichts mit kontextspezifischem Escaping zu tun.
Benutzerdaten in PHP-Variablen fallen für mich in die Kategorie "reiner Text". Egal ob das durch noch strengere Prüfungen der äußeren Form verschärft wurde. Wenn ich "reinen Text" in die Datenbank schreiben, muß ich immer damit rechnen, dass SQL-störende Sonderzeichen darin enthalten sind (warum auch immer - absichtlich oder durch Programmierfehler), und folglich ist Escaping zwingend angezeigt.
Dasselbe Spielchen gibts bei der HTML-Ausgabe. Die Inhalte der PHP-Variablen sind "reiner Text", können also HTML-störende Sonderzeichen enthalten. Folglich ist Escaping zwingend angezeigt, jetzt eben mit htmlspecialchars().
Dabei ist mir am Ort der Variablenausgabe (SQL, HTML, Dateinamen etc.) vollkommen egal, ob $username nur aus /[1]+$/ besteht. Ich vertraue einfach nicht den zu einer ganz anderen Zeit von evtl. einem ganz anderen Programmierer geschriebenen Subsystemen.
Zumal dieses grundsätzliche Escaping nicht nur eine zusätzliche Sicherheitsschicht ergibt, sondern auch die Prüfung des Usernamens vereinfacht: Ich muß nur noch meine Formprüfung beim Anlegen eines neuen Users vornehmen, und nur der geprüfte Username kann in die Datenbank gelangen. Alle weiteren lesenden Aktionen mit dem Usernamen hingegen kann ich auch formungeprüft in der Datenbank vornehmen - existierende User werden dort nur gefunden, wenn der aktuell angegebene Username der Form entspricht. Durch das Escaping (das sehr unaufwendig ist) spare ich mir das ständige Prüfen des Usernamens auf Einhaltung des Regex (was deutlich aufwendiger ist).
Natürlich hast du im Grundsatz deiner Überlegung recht: Wenn die einzigen Zeichen, die in $username vorkommen dürfen, immer unverändert durch das Escaping durchgehen, könnte man sich das Escaping auch sparen.
Aber ich halte eben absolut nichts davon, Sicherheitsmechanismen nur aufgrund von zufälligen, abänderbaren Überlegungen und Definitionen z.B. über den Inhalt eines Benutzernamens, zu umgehen. Wenn ich den Datenbanklayer programmiere, gehe ich reflexartig davon aus, dass alle mir übergebenen Daten böse Zeichen enthalten, und handle entsprechend.
Ich hatte das Beispiel Benutzername. Wenn ich weitere Fehlfunktionen ausschließen will (Prämisse: nur [a-zA-Z]), muß ich die Eingaben sowieso überprüfen. Warum dann noch escapen? Ich vertraue doch nicht darauf, ausschließlich zu escapen und daß die Eingabe schon ein valides Format haben wird.
Escaping ist keine Prüfung der Form. Aber die Prüfung der Form muß ja nicht überall stattfinden, wo du einen Benutzernamen übergeben bekommst - es reicht ja aus, dort zu prüfen, wo der Benutzername neu erzeugt wird (bzw. verändert werden kann).
Fehlerfreie Programmierung: Stimmt, es kann sinnvoll sein, Plausibilität zu prüfen und trotzdem escapen. Aber nicht bei einer so einfachen Sache wie einem Benutzername.
Um Escapingprobleme zu bekommen, reicht es doch schon aus, den RegEx fehlerhaft zu programmieren. Statt /[2]+$/ schreibst du vielleicht nur /[3]+/ - und schwups kann man dir SQL-aktive Zeichen unterschieben, die mit nachgeschaltetem Escaping absolut keine Wirkung haben - und ohne Escaping böse Sicherheitslücken reißen.
An wievielen Stellen taucht in deinem Code die Notwendigkeit zur Prüfung des Usernamens auf Einhaltung der Form auf? Hoffentlich nur an einer einzigen Stelle, aber vermutlich an mehreren. Die müssen alle synchron gehalten werden. Und spätestens dann, wenn der Username mehr Zeichen enthalten darf, weil das so gefordert ist, ist es doch ein deutlich beruhigenderes Gefühl, wenn die Datenbank nicht abkacken kann, weil der DB-Code noch escaping veranstaltet.
Es ist halt ein Erfahrungswert aus tausenden von programmierten Skripten: Die Datenbanksicherheit wird sehr häufig durch mangelndes Escaping gefährdet. Wenn man sich als Programmierer daher angewöhnt, variable Daten immer zu escapen, egal was drinsteht, wird man in diese Sicherheitsfalle nie mehr hineintappen. Das Gleiche gilt für die HTML-Ausgabe: Wenn man sich angewöhnt, variable Daten immer durch htmlspecialchars() zu entschärfen, wird man niemals unerwartet fremden HTML- oder Javascriptcode auf seiner Seite haben.
- Sven Rautenberg
"Love your nation - respect the others."