Fehlerhafte Benutzereingabe mit web.input

Django, Flask, Bottle, WSGI, CGI…
Antworten
moehre
User
Beiträge: 39
Registriert: Donnerstag 21. April 2016, 13:50

Hallo,

ich habe einen Webservice mit Web.py erstellt.
Nun möchte ich Benutzereingaben in meinem SQL-Statement verwenden. Dafür verwende ich web.input().

Code: Alles auswählen

data = web.input()
id = int(data.id)
...
cursor.execute(
    "SELECT a WHERE  a.id = id AND ...")
Die Eingabe besteht nur aus einem Wert der ID.
Allerdings erscheint bei mir die Fehlermeldung:
<class 'cx_Oracle.DatabaseError'> at /grid
ORA-00918: Spalte nicht eindeutig definiert


Wenn ich im SQL-Statement für a.id den Wert direkt definiere (a.id = 1) dann funktioniert es...Was mache ich falsch?
BlackJack

@moehre: An welcher Stelle soll denn da der Wert von `id` in die Abfrage kommen? Gehst Du davon aus das in der Zeichenkette auf magische Weise eines der 'id', und dann natürlich auch das richtige, durch den Wert von der Python-Variable `id` ersetzt wird? Du musst im SQL Platzhalter für Werte verwenden und die Werte selber dann als zweites Argument von `execute()` übergeben. Auf *keinen Fall* die Werte selbst mit Zeichenkettenoperationen in die Anfrage rein basteln. Auf die Weise können Benutzer Dir nahezu beliebige SQL-Anweisungen da rein schmuggeln. Stichwort SQL-Injection.
moehre
User
Beiträge: 39
Registriert: Donnerstag 21. April 2016, 13:50

Ok stimmt also definiere ich einen Platzhalter und übergebe im zweiten Schritt die ID...

Code: Alles auswählen

data = web.input()
id = int(data.ID)

query = "SELECT a.id ... FROM ...  WHERE   a.grid_id = %s;"

cursor.execute(query, id)
Aber das funktioniert auch nicht! Folgende Fehlermeldung erscheint:
TypeError: expecting a dictionary, sequence or keyword args
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@moehre: da hilft es, die Dokumentation zu execute zu lesen, denn dort steht geschrieben, dass das zweite Argument eine Sequenz (z.B. eine Liste) oder, falls Platzhalter mit Namen verwendet werden, ein Wörterbuch sein muß.
moehre
User
Beiträge: 39
Registriert: Donnerstag 21. April 2016, 13:50

Ok danke für den Hinweis.
Wen ich jetzt aber nur ein Integer gegeben habe und keine Sequenz oder Wörterbuch, wie kann ich das Problem dann umgehen?
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@moehre: eine Liste kann auch nur ein Element enthalten.
moehre
User
Beiträge: 39
Registriert: Donnerstag 21. April 2016, 13:50

Ok also wenn ich die Benutzereingabe so definiere:
data = web.input(ID="[]") ist doch eine List vorhanden oder?

Wenn ich die Abfrage ausführe (cursor.execute(query, data.ID))erscheint vollgende Fehlermeldung:
'ascii' codec can't decode byte 0xfc in position 36: ordinal not in range(128)
BlackJack

@moehre: Von dem Web-Objekt möchtest Du keine Liste sondern einen Wert den Du in eine Zahl umwandelst. Du bastelst da am falschen Ende. `execute()` möchte eine Liste mit einem Wert pro Platzhalter, das hat nichts damit zu tun wo dieser Wert ursprünglich herkommt. Du hast ja schon den ID-Wert, den musst Du in eine Liste stecken.
moehre
User
Beiträge: 39
Registriert: Donnerstag 21. April 2016, 13:50

Also ich habe ein Web-Objekt was ein String ist
1.)

Code: Alles auswählen

data = web.input()
Diesen wandele ich um in ein Integer
2.)

Code: Alles auswählen

id = int(data.ID)
Danach erstelle ich eine Liste a und füge den Wert hinzu
3.)

Code: Alles auswählen

a = [id]
Danach rufe ich den query auf
4.)

Code: Alles auswählen

query = "SELECT ...FROM...WHERE a.id = %s;"
Funktioniert soweit im Debug-Modus!

Wenn ich im 5ten Schritt den Cursor ausführen will
5.)

Code: Alles auswählen

cursor.execute(query, a)
erscheint die Fehlermeldung:
'ascii' codec can't decode byte 0xfc in position 36: ordinal not in range(128)

Der Parameter a im execute-Statement ist eine Liste die meine ID enthält...was ist jetzt noch falsch?
BlackJack

@moehre: Ein kompletter Traceback wäre nützlich um mehr darüber zu erfahren wo die Ausnahme genau auftritt. Ansonsten kann man nur raten, dass Du vielleicht irgendwo in der SQL-Anfrage etwas hast das sich nicht implizit dekodieren lässt, also irgendwas ausserhalb von ASCII‽
moehre
User
Beiträge: 39
Registriert: Donnerstag 21. April 2016, 13:50

Mein SQL-Query sieht so aus:

Code: Alles auswählen

SELECT a.id AS building_nr, c.geometry.sdo_ordinates AS geometry, d.Classname AS polygon_typ FROM   building a, THEMATIC_SURFACE b, SURFACE_GEOMETRY c, OBJECTCLASS d  WHERE   a.id = b.BUILDING_ID AND b.LOD2_MULTI_SURFACE_ID = c.ROOT_ID AND c.GEOMETRY IS NOT NULL AND b.OBJECTCLASS_ID = d.ID AND a.grid_id_500 = %s;"
Traceback:
Traceback (innermost first)

C:/Users/53_D_ML/Desktop/Masterthesis_15.06/wwwroot/REST\web\utils.py in safeunicode
return unicode(obj) ...
▶ Local vars
C:/Users/53_D_ML/Desktop/Masterthesis_15.06/wwwroot/REST\web\template.py in _escape
value = safeunicode(value) ...
.......
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@moehre: der Fehler tritt ja irgendwo im Template auf, also bei der Ausgabe, hat also erstmal nichts mit Deiner SQL-Abfrage zu tun. Da wäre es nunmal gut, Deinen gesamten Code und den kompletten Traceback zu sehen.

Übrigens sollte Programmcode NIEMALS in einem Dokumentenverzeichnis (wwwroot) liegen, auf das man auch direkt per Web-Server zugreifen kann oder potentiell wegen einer leicht falschen Konfiguration zugreifen könnte. Mit Hilfe des Programmcodes kann nämlich ein Angreifer viel einfacher nach Schwachstellen suchen, bzw. findet er im Zweifel sogar Passwörter, die im Programm benutzt werden.
moehre
User
Beiträge: 39
Registriert: Donnerstag 21. April 2016, 13:50

Also mein Code sieht folgendermaßen aus:

Code: Alles auswählen

import cx_Oracle
import json
import web

urls = (
    "/grid", "grid"
)
app = web.application(urls, globals())
web.config.debug = True

connection = cx_Oracle.Connection("user/pssw@10.40.33.160:1521/sdetest", )
typeObj = connection.gettype("MDSYS.SDO_GEOMETRY")

class grid:
    def GET(self):
        web.header('Access-Control-Allow-Origin',       '*')
        web.header('Access-Control-Allow-Credentials', 'true')
        web.header('Content-Type', 'application/json')
		
	data = web.input()
        id = int(data.ID)
        a = [id]

        cursor = connection.cursor()
        cursor.arraysize = 10000

	query = "SELECT a.id AS building_nr, c.geometry.sdo_ordinates AS geometry, d.Classname AS polygon_typ FROM   building a, THEMATIC_SURFACE b, SURFACE_GEOMETRY c, OBJECTCLASS d  WHERE   a.id = b.BUILDING_ID AND b.LOD2_MULTI_SURFACE_ID = c.ROOT_ID AND c.GEOMETRY IS NOT NULL AND b.OBJECTCLASS_ID = d.ID AND a.grid_id_500 = %s;"

	cursor.execute(query,a) 
	result = []

	for id,geometry , classname in cursor:
	        result.append({"building_nr":id,"geometry":{"type":"polygon","coordinates":zip(*[iter(geometry.aslist())]*3),},"polygon_typ":classname,})
        return json.dumps(result)

if __name__ == "__main__":
    app.run()
Der Programmcode liegt auf einer Kopie des Dokumentenverzeichnisses wwwroot. Es ist nicht das originale.

Traceback
<type 'exceptions.UnicodeDecodeError'> at /grid
'ascii' codec can't decode byte 0xfc in position 36: ordinal not in range(128)
Python C:\Users\53_D_ML\Desktop\Masterthesis_15.06\wwwroot\REST\web\utils.py in safeunicode, line 351
Web GET http://localhost:8080/grid
Traceback (innermost first)

C:\Users\53_D_ML\Desktop\Masterthesis_15.06\wwwroot\REST\web\utils.py in safeunicode
return unicode(obj) ...
▼ Local vars
Variable Value
encoding
'utf-8'
obj
DatabaseError(<cx_Oracle._Error object at 0x02C7BBE0>,)
t
<class 'cx_Oracle.DatabaseError'>
C:\Users\53_D_ML\Desktop\Masterthesis_15.06\wwwroot\REST\web\template.py in _escape
value = safeunicode(value) ...
▼ Local vars
Variable Value
escape
True
self
<web.template.Template instance at 0x02A68C88>
value
DatabaseError(<cx_Oracle._Error object at 0x02C7BBE0>,)
C:\Users\53_D_ML\Desktop\Masterthesis_15.06\wwwroot\REST\web\debugerror.pyc in __template__

▶ Local vars
C:\Users\53_D_ML\Desktop\Masterthesis_15.06\wwwroot\REST\web\debugerror.py in djangoerror

return t(exception_type, exception_value, frames) ...

▶ Local vars
C:\Users\53_D_ML\Desktop\Masterthesis_15.06\wwwroot\REST\web\debugerror.py in debugerror

return web._InternalError(djangoerror()) ...

C:\Users\53_D_ML\Desktop\Masterthesis_15.06\wwwroot\REST\web\application.py in internalerror

return debugerror.debugerror() ...

▶ Local vars
C:\Users\53_D_ML\Desktop\Masterthesis_15.06\wwwroot\REST\web\application.py in process

raise self.internalerror() ...

▶ Local vars
C:\Users\53_D_ML\Desktop\Masterthesis_15.06\wwwroot\REST\web\application.py in <lambda>

return p(lambda: process(processors)) ...

▶ Local vars
C:\Users\53_D_ML\Desktop\Masterthesis_15.06\wwwroot\REST\web\application.py in processor

return handler() ...

▶ Local vars
C:\Users\53_D_ML\Desktop\Masterthesis_15.06\wwwroot\REST\web\application.py in process

return p(lambda: process(processors)) ...

▶ Local vars
BlackJack

@moehre: Wenn ich das richtig sehe tritt der Fehler bei der Behandlung eines Fehlers auf. Was sagt denn das Fehlerprotokoll des Webservers dazu?
moehre
User
Beiträge: 39
Registriert: Donnerstag 21. April 2016, 13:50

Wie kriege ich denn das Fehlerprotokoll?
BlackJack

@moehre: Das hängt vom Webserver und dessen Konfiguration ab.
moehre
User
Beiträge: 39
Registriert: Donnerstag 21. April 2016, 13:50

Es liegt wohl an der API cx_Oracle!
Hier wird einiges anders gehandhabt.

Ich habe es jetzt nach langem probieren zum laufen bekommen:

Code: Alles auswählen

data = web.input(ID='')
query = "SELECT....FROM ...WHERE a.id =:grid_ID"
cursor.execute(query, {'grid_id':data.ID})
BlackJack

@moehre: Was heisst ”anders”, es verwendet halt 'named' als Parameterstil, das hätte man halt in der Dokumentation nachlesen können/müssen.

Ich nehme wegen solcher Details ganz gerne SQLAlchemy als Abstraktion über die DB API 2.0. Da wäre dann aber die Frage wie man dort mit den GEO-Typen umgeht, die ja nicht zum SQL-Standard gehören.
Antworten