psycopg2 und create database, create role, ...

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
tkwolf
User
Beiträge: 2
Registriert: Donnerstag 4. November 2010, 16:48

Hallo!

Ich habe wirklich lange bei Google und im Forum gesucht, um eine antwort zu finden, versprochen :)

Es geht um das SQL-Injection Problem bei der Benutzung von psycopg2 mit Variablen.
Soweit ich das verstanden hab, braucht man sich darum gar keine Gedanken zu machen, wenn man den zweiten Parameter von execute() benutzt.
Leider funktioniert so ein Aufruf
cur.execute(CREATE_DB, (db_name, )) mit einer Fehlermeldung wie
"CREATE DATABASE E'<db_name>' [...]" mit einem Fehler bei E' nicht.

Mit
cur.execute(CREATE_DB % db_name)
geht es natürlich. Aber das soll man ja laut manual "never never nerver" machen.
Wie denn sonst? Gibt es da eine übliche Vorgehensweise? In meiner Verzweiflung würde ich jetzt den zweiten, funktionierenden Aufruf stehen lassen und db_name vorher mit der re r'.*[;\'\\].*' auf Sicherheit prüfen...
Ich muss in meiner Datenbank unbedingt Datenbanken erzeugen, löschen und rollen erzeugen, löschen können. Eingaben kommen von Usern einer Webseite, daher kann ich den Strings nicht trauen.

Danke schonmal :)
BlackJack

@tkwolf: Zeig doch mal bitte die vollständigen Informationen. Wie sieht das SQL aus? Wie der Wert, den Du da einsetzen möchtest, und wie der komplette Traceback?
tkwolf
User
Beiträge: 2
Registriert: Donnerstag 4. November 2010, 16:48

Na, viel gibts da nicht zu zeigen:

Code: Alles auswählen

>>> import psycopg2
>>> conn = psycopg2.connect(*zensiert*)
>>> CREATE_DB = "CREATE DATABASE %s"
>>> db_name = 'testdatenbank'

>>> cur = conn.cursor()
>>> cur.mogrify(CREATE_DB, (db_name, )) # Methode 1
"CREATE DATABASE E'testdatenbank'"
>>> cur.execute(CREATE_DB, (db_name, ))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
psycopg2.ProgrammingError: syntax error at or near "E'testdatenbank'"
LINE 1: CREATE DATABASE E'testdatenbank'
                        ^
>>> cur.mogrify(CREATE_DB % db_name) # Methode 2
'CREATE DATABASE testdatenbank'
>>> cur.execute(CREATE_DB % db_name)
Methode 1 macht brav String-Escape mit diesem "E'<string>'". Da meckert jedoch PostgreSQL (tut es auch, wenn ich den Befehl per Hand in psql eingebe).
Methode 2 funktioniert problemlos, aber das soll man ja "never never never" machen.

Offensichtlich dürfen Bezeichner für Datenbanken und Rollen nicht escaped werden, denn da passiert das gleiche:

Code: Alles auswählen

>>> CREATE_ROLE = "CREATE ROLE %s WITH NOSUPERUSER LOGIN PASSWORD %s"
>>> user = "ich"
>>> passwort = "geheim"
>>> cur.mogrify(CREATE_ROLE, (user, passwort)) # Methode 1
"CREATE ROLE E'ich' WITH NOSUPERUSER LOGIN PASSWORD E'geheim'"
>>> cur.execute(CREATE_ROLE, (user, passwort))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
psycopg2.ProgrammingError: syntax error at or near "E'ich'"
LINE 1: CREATE ROLE E'ich' WITH NOSUPERUSER LOGIN PASSWORD E'geheim'
                    ^
>>> CREATE_ROLE = "CREATE ROLE ich WITH NOSUPERUSER LOGIN PASSWORD %s" # Methode 2
>>> cur.mogrify(CREATE_ROLE, ( passwort, ))
"CREATE ROLE ich WITH NOSUPERUSER LOGIN PASSWORD E'geheim'"
>>> cur.execute(CREATE_ROLE, ( passwort, ))
Methode 1 versagt kläglich, Methode 2 geht wieder. Man sieht, dass das Passwort sehrwohl escaped werden darf.

Ist es von den Entwicklern nicht vorgesehen, dass man z.B. Datenbanken und Rollen mit psycopg2 erstellt? Oder ist das so ein Fall wie "Oh, du bist so Fortgeschritten und machst CREATE DATABASE und so? Dann ignorier halt das Verbot aus der Doku und setze Strings direkt ein!"

Es besteht grade gar kein praktisches Problem. User und DB-Namen werden bei mir sowieso auf r'^[a-zA-Z0-9_]+' gefiltert und Passwörter werden ja escaped. Es interessiert mich nur prinzipiell, wie es gedacht ist, unter psycopg2 solche Befehle, wo Strings nicht escaped werden dürfen, zu handhaben sind.
Antworten