phpbar.de logo

Mailinglisten-Archive

[php] sichere MySQL Queries

[php] sichere MySQL Queries

AA aa at geb-team.de
Don Nov 9 16:36:10 CET 2006


hallo lutz,

 > Das ist eben genau der entscheidende Denkfehler... Du mußt jedes Feld
 > "escapen". Der Grund ist einfach: Wer garantiert Dir, daß dort, wo Du
 > im SQL-Befehl eine Zahl vorgesehen hast, auch eine Zahl ankommt und
 > nicht etwa eine eingeschleuste Zeichenkette à la '1 OR 1=1'? Es ist ein
 > gravierender Denkfehler, sich nur auf die Textfelder zu konzentrieren.

gravierender denkfehler? hast du schonmal versucht den typ int über ein 
formular zu versenden? alles was darüber ankommt ist vom typ "string" 
und muss entsprechend gecastet und/oder geprüft werden vor der 
speicherung. zb. mit den hübschen filter-funktionen, die seit 5.2 per 
default mitgeliefert werden: http://www.php.net/manual/en/ref.filter.php

und wenn ich ein integer in die datenbank einfüge, dann füge ich ein 
integer ein und keinen string, den ich escapen muss. bei meinen 
ausführungen wolle ich keine abhandlung über typen schreiben oder ein 
anfängerhandbuch, sondern habe mich darauf verlassen, dass die 
mitlesenden sehr wohl zwischen einem string und int o.ä. unterscheiden 
können. da ich hier schon weile mitlese, weiss ich, dass ich gerade dir 
den unterschied nicht erklären muss und du sehr wohl verstehst, was 
"mein" kurzer merksatz zu bedeuten hat:

"text, der in eine db gespeichert wird, muss escaped werden."

dabei sollte man es auch bewenden lassen, denn mit text meine ich 
natürlich strings, also alles, was über formulare zb. kommt, auch wenn 
man dort noch soviele zahlen reinschreibt ;)

zu deinen bemerkungen bezügl. prepared statements:
--------------------------------------------------
ich wollte dir mit meinem hinweis keinesfalls auf die füsse treten. ich 
bezog mich auf prepared statement anweisungen der mysqli-erweiterung. 
das wurde ja hier erwähnt als möglichkeit.
ich meine, es ist gestattet, darauf hinzuweisen, dass dies keine 
wirkliche lösung ist, sondern für den einzelfall ausreichend. wer heute 
komplexe anwendungen basierend auf der mysqli-erweiterung schreibt (zb. 
ich *g*), der wird es morgen schwer haben, dies mal eben zu portieren, 
weil eben einige mysqli-anweisungen so speziell auf mysql zugeschnitten 
sind, dass man das nicht eben mal so austauschen kann. auch nicht mit 
PDO (siehe zb. mysqli_field_seek() u.v.a. spielereien, die ich nicht 
missen möchte).

es ist müssig, darüber zu diskutieren, welches die *beste* variante ist. 
es gibt nämlich keine. nur eben grundsätze, die zu beachten sind.

etwas, was ich noch nicht erwähnt hatte, sind nicht angriffe in form von 
"unerwarteten" formularinhalten, sondern auch gern übersehene und nicht 
geprüfte feldlängen. wir können als php-entwickler nicht enfach sagen, 
dass ist kein problem, was ich nicht beeinflussen kann: zb. wissen wir 
nicht, wie mysql oder eine andere systemkomponente mit unerwartet hohen 
paketen umgeht. also wenn ich über ein formularfeld statt dem erwarteten 
nachnamen einen 8MB-langen string abschicke. ist es dann möglich über 
einen fehler des mysql-servers schadcode einzuschleusen? wir wissen es 
nicht und können dies nicht wissen. wir können und müssen daher 
tatsächlich jeden input genauestens prüfen, egal von welchem typ er kommt.

Lutz Zetzsche wrote:
> Hallo AA,
> 
> Am Donnerstag, 9. November 2006 14:30 schrieb AA:
>> zum semikolon-märchen:
>> ----------------------
>> das mit dem semikolon im query ist eine legende. mysql und mysqli
>> filtern dies heraus. das steht auch im handbuch:
>>
>> "The query string should not end with a semicolon."
> 
> da steht nur, daß am Ende kein Semikolon stehen *sollte*. Von Filtern 
> ist da keine Rede. Nach meiner Erinnerung hat Peter recht, daß es - 
> zumindest bei der mysql-Erweiterung - tatsächlich zu einer 
> Fehlermeldung kommt, wenn der Query-String ein abschließendes Semikolon 
> enthält.
> 
>> aus bestimmten gründen, kann dies aber gewollt sein (mehrere queries
>> in einem befehl). dafür liefert mysqli die funktion/methode
>> mysqli_multi_query() / multi_query():
>>
>> "executes one or multiple queries which are concatenated by a
>> semicolon."
> 
> In dem Augenblick hätten wir dann aber auch  potentiell genau das 
> Sicherheitsloch, um das es Michael in seiner Frage ging. ;-)
> 
>> zum einsatz von prepared statements als heilmittel:
>> ---------------------------------------------------
>> schickes feature :)
> 
> Ich sagte nicht, daß es sich um ein Allheilmittel handelt, allerdings 
> halte ich Prepared Statements für die sicherste Methode, 
> SQL-Einschleusung zu vermeiden. Mir ist klar, daß das bei nur einmal 
> ausgeführten SQL-Befehlen zu einem Performanzverlust führt, jedoch 
> bewerte ich persönlich den Sicherheitsgewinn deutlich höher. Wen es 
> interessiert, kann ja auch mal auf der MySQL-Website nachlesen und sich 
> sein eigenes Bild machen:
> 
> http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html
> 
>> was dagegen spricht: will man eine portable anwendung schreiben (zb.
>> mit der PDO-erweiterung), sollte man dies tunlichst unterlassen.
>> leider findet sich dieser entscheidende hinweis nicht überall da, wo
>> er hingehört. aber zumindest wird es bei PDO-mysql in einem nebensatz
>> erwähnt:
>>
>> "If you're writing portable code, you should use
>> PDOStatement::fetchAll() instead."
> 
> Möglicherweise habe ich von der Materie zu wenig Ahnung, aber aus meiner 
> Sicht hast Du hier etwas falsch interpretiert. Dieser Satz bezieht sich 
> auf die vordefinierte Konstante PDO::MYSQL_ATTR_USE_BUFFERED_QUERY und 
> steht auf folgender Seite:
> 
> 	http://de3.php.net/manual/en/ref.pdo-mysql.php
> 
> Zum einen handelt es sich hier also um eine MySQL-spezifische Konstante 
> und zum anderen vermute ich, daß man sie im Zusammenhang mit Prepared 
> Statements auf TRUE setzen kann, aber nicht muß.
> 
> Viel wichtiger erscheint mit folgendes Zitat von der 
> PDO-Einführungsseite:
> 
> "Prepared statements are so useful that they are the only feature that 
> PDO will emulate for drivers that don't support them. This ensures that 
> you will be able to use the same data access paradigm regardless of the 
> capabilities of the database."
> -> http://de3.php.net/manual/en/ref.pdo.php
> 
> Wenn das so ist, dann ist die Portabilität auch bei der Verwendung von 
> Prepared Statements doch grundsätzlich erst einmal gewährleistet. 
> Andersherum formiliert: Die PDO-Erweiterung soll ja gerade die 
> Portabilität gewährleisten. Würde die Verwendung von Prepared 
> Statements dieses Ziel zunichte machen, gäbe es sicherlich nicht die 
> Möglichkeit, diese mit PDO zu verwenden.
> 
> Ein weiterer Punkt ist, daß es wahre Portabilität wohl nur schwerlich 
> gibt. Selbst Hibernate erreicht sie nicht. Es gibt nur eine 
> größtmögliche Annäherung. ;-)
> 
>> zur eigentlichen frage: "sichere mysql-queries?"
>> ------------------------------------------------
>> das ist ein komplexes thema und lässt sich nicht mit einer formel
>> beantworten. es gibt allerdings eine grundregel: text, der in ene db
>> gespeichert wird, muss escaped werden.
> 
> Das ist eben genau der entscheidende Denkfehler... Du mußt jedes Feld 
> "escapen". Der Grund ist einfach: Wer garantiert Dir, daß dort, wo Du 
> im SQL-Befehl eine Zahl vorgesehen hast, auch eine Zahl ankommt und 
> nicht etwa eine eingeschleuste Zeichenkette à la '1 OR 1=1'? Es ist ein 
> gravierender Denkfehler, sich nur auf die Textfelder zu konzentrieren.
> 
> 
> Viele Grüße
> Lutz

php::bar PHP Wiki   -   Listenarchive