Teile einer Abfrage über raw_Input()
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
So eine "Es wird ja schon nichts passieren"-Mentalität ist eben der Grund, warum es zu SQL-Injections kommt. Wenn du nicht quotest, hast du eine Sicherheitslücke - so einfach ist das. Und nein,`MySQLdb.OperationalError` zu testen ist keine tolle Idee um sich das zu ersparen, denn 'DROP TABLE Indizes;' gibt keinen Fehler zurück, es funktioniert einfach.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hallo meneliel!meneliel hat geschrieben:Noch zum gleichen Problem: ein Freund hat jetzt noch ganz doll geschimpft mit mir, dass ich doch nicht einfach den User per Eingabe Teile einer Abfrage formulieren lassen kann, ohne das abzuchecken.
Er hat natürlich Recht. Und deshalb musst du abwiegen, ob du dich darum kümmern musst oder nicht. So etwas ist immer dann gefährlich, wenn du etwas übers Internet machen möchtest oder wenn dieses Programm von Benutzern bedient werden muss, denen du nicht komplett vertraust.
Wenn du dieses Programm aber nur für dich und ein paar vertrauenswürdige Freunde schreibst, dann ist das kein Problem.
Ist das nicht der Fall, dann lasse ich die Benutzer des Programms **keinen** Teil des SQL-Strings direkt eingeben. Ich biete Werte zur Auswahl an. Fazit: Programme für nicht vertrauenswürdige Benutzer sind immer umständlicher zu schreiben als Programme für vertrauenswürdige Benutzer.
mfg
Gerold
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Mit dem MySQLdb.OperationalError, kann ich aber zumindest "falsche" Eingaben abfangen, da reicht ja nen Tippfehler.
Wie verhinder ich nun Injections? Ich könnt z.B. checken, ob beim raw_input() ein ";" vorkommt und dann schon abbrechen?*
Gefahr besteht ja in dem Fall auch nur für die erste Abfrage, da die anderen beiden über vorkommen der Eingabe in einem Dictionary geprüft werden.
EDIT: * oder ich pack alle "bösen KEywords" in eine Liste, z.B. UPDATE, DELETE; ALTER TABLE;DROP, was auch immer und gucke halt ob eins der Wörter dann in der Eingabe vorkommt... wäre das ein Idee, das das Problem lösen könnte?
Wie verhinder ich nun Injections? Ich könnt z.B. checken, ob beim raw_input() ein ";" vorkommt und dann schon abbrechen?*
Gefahr besteht ja in dem Fall auch nur für die erste Abfrage, da die anderen beiden über vorkommen der Eingabe in einem Dictionary geprüft werden.
EDIT: * oder ich pack alle "bösen KEywords" in eine Liste, z.B. UPDATE, DELETE; ALTER TABLE;DROP, was auch immer und gucke halt ob eins der Wörter dann in der Eingabe vorkommt... wäre das ein Idee, das das Problem lösen könnte?
WESSEN Tippfehler ist hier die Frage. Der User DARF durch egal was für eingaben keinen OperationalError verursachen.Mit dem MySQLdb.OperationalError, kann ich aber zumindest "falsche" Eingaben abfangen, da reicht ja nen Tippfehler.
Indem du es nicht selber machst, sondern die API machen lässt, wie schon erwähnt, indem du nichtWie verhinder ich nun Injections? Ich könnt z.B. checken, ob beim raw_input() ein ";" vorkommt und dann schon abbrechen?*
sonderncursor.execute('select AGS, Datum, AREA, ID from ebenen where (DES = %s)' % sel_ebene)
machst.cursor.execute('select AGS, Datum, AREA, ID from ebenen where (DES = %s)', sel_ebene)
Der kleine, aber feine unterschied ist, dass beim ersten mal execute einen string bekommt, bei dem du (per %) die Ersetzungen auf unsichere Art gemachst hast, beim zweiten bekommt execute einen string, und argumente, die es dareinschreiben soll, und kümmert sich darum, dass die ' escaped werden, etc.
es gibt keine "bösen keywords". Ein insert kann deine datenbank genau so inkonsistent (=unbrauchbar) machen, wie ein delete.oder ich pack alle "bösen KEywords" in eine Liste
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hallo keppla!keppla hat geschrieben:Indem du es nicht selber machst, sondern die API machen lässt
Damit kannst du nur Werte ersetzen lassen. Tabellennamen oder Feldnamen kannst du damit nicht ergänzend in die SQL-Anweisung einfügen, da ein Text immer in Anführungszeichen gesetzt wird.
mfg
Gerold
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Man müsste eben selbst quoten (ich habe jetzt auch nichts gefunden, das das erledigt - warscheinlich hat aber das DB-API 2.0 konforme Modul da schon etwas fertiges).
Wenn du es aber selbst implementierst kannst du dich ja orientieren was PgQuoteString macht.
Wenn du es aber selbst implementierst kannst du dich ja orientieren was PgQuoteString macht.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
öhm ... k ....Leonidas hat geschrieben:Man müsste eben selbst quoten (ich habe jetzt auch nichts gefunden, das das erledigt - warscheinlich hat aber das DB-API 2.0 konforme Modul da schon etwas fertiges).
Wenn du es aber selbst implementierst kannst du dich ja orientieren was PgQuoteString macht.
*verwirrt guck* ... damit kann ich jetzt gerade irgendwie gar nix anfangen
Ich glaub dann geht es doch einfacher und schneller ich beschränke die Eingabemöglichkeiten noch mehr ... so wie Gerold das macht, also Auswahlmöglicheiten stellen ... ...
(will/muss bis Ende Dezember mit Programmieren fertig sein für das Projekt und das mit dem selber quoten dauert dann wohl doch etwas länger, bis verstanden und umgesetzt, kommt aber auf jeden Fall mit auf die ToDO Liste zum angucken für danach )
Danke euch allen.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Ich habe doch gesagt, dass selbst quoten in aller Regel nicht so einfach ist.
An sich ist es aber auch nicht so schwer, man muss nur unter Umständen "gefährliche" Zeichen, die nicht erlaubt sind escapen. Also etwa einen Backslash durch zwei, ein Quote durch ein escapetes-Quote, Tab als \t, etc.
An sich ist es aber auch nicht so schwer, man muss nur unter Umständen "gefährliche" Zeichen, die nicht erlaubt sind escapen. Also etwa einen Backslash durch zwei, ein Quote durch ein escapetes-Quote, Tab als \t, etc.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Ja, das ist mir klar. Aber warum sollte ich tabellen- oder feldnamen escapen wollen? Wie sieht eine software aus, wo solche namen aus nicht vertrauenswürdigen Quellen kommen?gerold hat geschrieben:Damit kannst du nur Werte ersetzen lassen. Tabellennamen oder Feldnamen kannst du damit nicht ergänzend in die SQL-Anweisung einfügen, da ein Text immer in Anführungszeichen gesetzt wird.keppla hat geschrieben:Indem du es nicht selber machst, sondern die API machen lässt
<loriot>ach?</loriot>Na da wo sie ein Anwender eingeben kann.
Ernsthaft: warum sollte man soetwas tun? Wenn ein Anwender bestimmen kann, auf welche Tabellen oder Felder queries losgelassen werden können, hilft escaping auch nicht mehr.
Um es mal plakativ darzustellen:
Code: Alles auswählen
delete from %s where %s = %s
Und selbst _wenn_ es denn nötig sein sollte, braucht man da kein escaping, sondern nur eine positivliste:
Code: Alles auswählen
cursor = conn.cursor()
conn.execute('show tables')
tables = set(row[0] for row in conn.fetchall)
table = raw_input("auf welche tabelle soll der query losgelassen werden?")
if not table in tables:
raise Exception("es sollte schon eine Tabelle sein")
cursor.execute("select * from %s" % table)
for row in cursor.fetchall():
print row
So etwas sollte man natürlich nicht tun wollen. Was aber nicht jeden davon abhält.
keppla hat geschrieben: Ernsthaft: warum sollte man soetwas tun? Wenn ein Anwender bestimmen kann, auf welche Tabellen oder Felder queries losgelassen werden können, hilft escaping auch nicht mehr.
oh je oh je .... das will ich doch gar nicht
Alles was gehen soll, ist, das Teile des Where-Teiles formuliert werden sollen. Und das versuche ich so mininal wie möglich zu halten. Hab ich bei dem 2. Teil halt auch geschafft.
Ich will nur Indikatoren berechnen*, aus einer passenden Tabelle, wo die alle drin stehen, aber halt nicht alle auf einmal, sondern ich möchte das beschränken auf Kategorien - und da gibt es nicht nur eine, sondern 2 pro Indikator. Das kann am Ende recht viel werden. Also nicht nur KAT1 ="a" sondern vielleicht Kat 1 ="a" and (Kat2 ="A" OR Kat2 ="C"). Könnte aber auch sein, dass ich nru einen einzigen Indikator direkt selektiere über seine ID ... und das macht es irgenwie gerade etwas kompliziert ...
Funktioniert ja nun auch mit den Templates ganz gut ... eigentlich ... wenn man brav ist und/oder weiß was man tut ... Und so lange nur ich damit arbeite ist das auch okay. ... nur werde auf Dauer ich nicht allein damit arbeiten, nehme ich an...
* das eigentliche Berechnen sind im Prinzip das eigentlich zu lösende Problem... das Selektieren aus der Datenbank brauch ich nur um an die Argumente zu kommen, die der Funktion dann übergeben werden
*etwas hilflos guck* ... oh je oh je ... Ich versteh das mit dem escapen und quoten grade überhaupt nicht.... also so überhaupt nicht, dass ich gar nicht weiß was Ihr eigentlich meint und wie mir das jetzt weiterhelfen soll ... *schäm*
Minimal scheint mir das nicht.meneliel hat geschrieben:Alles was gehen soll, ist, das Teile des Where-Teiles formuliert werden sollen. Und das versuche ich so mininal wie möglich zu halten. Hab ich bei dem 2. Teil halt auch geschafft.
nicht unbedingt.Ich will nur Indikatoren berechnen*, aus einer passenden Tabelle, wo die alle drin stehen, aber halt nicht alle auf einmal, sondern ich möchte das beschränken auf Kategorien - und da gibt es nicht nur eine, sondern 2 pro Indikator. Das kann am Ende recht viel werden. Also nicht nur KAT1 ="a" sondern vielleicht Kat 1 ="a" and (Kat2 ="A" OR Kat2 ="C"). Könnte aber auch sein, dass ich nru einen einzigen Indikator direkt selektiere über seine ID ... und das macht es irgenwie gerade etwas kompliziert ...
in mysql kann man statt
Code: Alles auswählen
(kat = "1" or kat="2" ... or kat="n")
Code: Alles auswählen
kat in (1, 2, ... n)
Code: Alles auswählen
query = "select * from tabelle where kat1 in %s and kat2 in %s"
values = (["A"], ["A", "C"])
cursor.execute(query, values)
also funktioniert es NICHT. Es bricht lediglich nicht sofort zusammen.Funktioniert ja nun auch mit den Templates ganz gut Smile ... eigentlich ... wenn man brav ist und/oder weiß was man tut
Bitte nicht falsch verstehen, das geht nicht gegen dich persönlich. Nur ist es einfach dumm, den komplizierten unsicheren weg, anstatt den einfachen, sicheren Weg zu gehen.
Escaping ist (ohne sql drumrum, plain python) z.B. sowas:*etwas hilflos guck* ... oh je oh je ... Ich versteh das mit dem escapen und quoten grade überhaupt nicht.... also so überhaupt nicht, dass ich gar nicht weiß was Ihr eigentlich meint und wie mir das jetzt weiterhelfen soll ... Embarassed *schäm*
Code: Alles auswählen
text = 'hallo \'welt\''
Bei sql hast du bei der "manuellen" ersetzung eben das Problmen, dass der user ' eingeben kann, und sql dann einen Teil seiner eingabe als befehl sieht.
Denke dir einen sql-string, der so aussieht:
Code: Alles auswählen
query = "select id from users where name='%s' and password='%s'"
Code: Alles auswählen
query %= ("egal' or 1=1 --", "völlig egal")
print query # select id from users where name = 'egal' or 1=1 --'and password='völlig egal'
Auch, wenn man davon ausgehen könnte, dass alle user gutartig wären, müsste man sich drum kümmern, denn sonst kommt früher oder später ein user namens O'Hara daher, und macht völlig gutartigerweise eine Eingabe, die das Programm abschmieren lässt.
Aber, weil das Problem so häufig ist, hat unsere db-api da schon was vorbereitet, nämlich den zweiten Parameter der execute-Methode.
Wenn du
Code: Alles auswählen
c.execute("insert into users set name = %s", ["O'Hara"])
Zuletzt geändert von keppla am Dienstag 11. Dezember 2007, 22:30, insgesamt 1-mal geändert.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
So wie ich das sehe ist beim Escapen von SQL mehr nötig als nur die Apostrophe zu escapen, zumindest macht das von mir verlinkte Modul einige Sachen mehr.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Ich wollte es eigentlich auch nicht darauf reduzieren, ich hätte häufiger z.B. sagen sollen. Ich wollte nur anhand der Apostrophe die Problematik erklärenLeonidas hat geschrieben:So wie ich das sehe ist beim Escapen von SQL mehr nötig als nur die Apostrophe zu escapen
Reicht das standardquoting von execute und co nicht aus?zumindest macht das von mir verlinkte Modul einige Sachen mehr.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Was ist das "Standardquoting"? Ich denke, was `execute()` quotet ist ihm selbst überlassen, das heißt jedem Modul das es implementiert. Ich könnte mir vorstellen, dass die Module ganz unterschiedlich quoten - wollte zwar im Quellcode von psycopg2 nachschauen, aber dann hat sich herausgestellt dass das im C-Part implementiert zu sein scheint und dann hatte ich keine Lust mehr weiterzugucken.keppla hat geschrieben:Reicht das standardquoting von execute und co nicht aus?zumindest macht das von mir verlinkte Modul einige Sachen mehr.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Ja, aber wir waren hier bei MySQL, und ich würde doch hoffen, dass das und die sonstigen gängigen apis da "vernünftig" handeln.Leonidas hat geschrieben:Was ist das "Standardquoting"? Ich denke, was `execute()` quotet ist ihm selbst überlassen, das heißt jedem Modul das es implementiert.keppla hat geschrieben:Reicht das standardquoting von execute und co nicht aus?zumindest macht das von mir verlinkte Modul einige Sachen mehr.
Hättest du da ein Gegenbeispiel?
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Ja, sicherlich. Ich wollte nur betonen dass es womöglich nicht reicht einfach nur ' zu quoten. Daher sollte man sich umso mehr auf das Quoting des Moduls stützen.keppla hat geschrieben:Ja, aber wir waren hier bei MySQL, und ich würde doch hoffen, dass das und die sonstigen gängigen apis da "vernünftig" handeln.
Hättest du da ein Gegenbeispiel?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
ALSO ... nach noch einem Tipp von Keppla, und weiterer verbaler Prügel von Kollegen, ich könne dem USer bitte GAR nichts überlassen, egal ob da außer mir nur noch 1-2 andere jemals das Programm benutzen, hab ich mich jetzt doch hingesetzt und
1. eine Oberfläche zusammengebastelt, wo wirklich NICHTS weiter, außer NUR die Werte selber eingegeben werden.
und
2. die querys gestückelt zusammengebastelt, und das sieht nun so aus:
(also nur der kleine Ausschnitt:)
geht bestimmt wieder viel toller und kompakter.
Mich stört das i+=1 noch. Das krieg ich bestimtm gleich mit in die for schleife rein, aber irgendwie steh ich auch gerade auf dem Schlauch und ganzen tag Oberfläche zusammenbasteln schlaucht ...
Ist das so nun besser? und sicherer?
1. eine Oberfläche zusammengebastelt, wo wirklich NICHTS weiter, außer NUR die Werte selber eingegeben werden.
und
2. die querys gestückelt zusammengebastelt, und das sieht nun so aus:
(also nur der kleine Ausschnitt:)
Code: Alles auswählen
elif indikator.get() == "category":
where_i = 'select * from indizes where 1=1'
# calc_cat
c_list = calc_cat_entry.get().split(",")
if len(c_list) > 0:
i_values=[]
where_i +=" and ("
i = 0
for c in c_list:
where_i +="calc_cat = %s"
i_values.append(c.lower())
i +=1
if len(c_list)-i > 0:
where_i +=" or "
where_i +=")"
# kategorie
k_list = kat.get().split(",")
# ... hier dann genau so, wie oben ....
cursor.execute(where_i, i_values)
Mich stört das i+=1 noch. Das krieg ich bestimtm gleich mit in die for schleife rein, aber irgendwie steh ich auch gerade auf dem Schlauch und ganzen tag Oberfläche zusammenbasteln schlaucht ...
Ist das so nun besser? und sicherer?