Schutz vor SQL Injection

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
TagiruAkashi
User
Beiträge: 12
Registriert: Dienstag 31. Januar 2012, 18:58

Hi

Ich habe gegenwärtig ein paar SQL Abfragen in meiner Anwendung über die eine Injection möglich wäre... jetzt habe ich gelesen das man sich davor mit folgender Syntax schützen kann...

Code: Alles auswählen

c.execute("""SELECT spam, eggs, sausage FROM breakfast
          WHERE price < %s""", (max_price,))
Wichtig soll hierbei das ',' hinter """ sein. Leider funktioniert bei mir nur folgendes

Code: Alles auswählen

c.execute("""SELECT spam, eggs, sausage FROM breakfast
          WHERE price < %s""" % (max_price,))
Allerdings soll das wohl falsch sein bzw. keinen Schutz bieten... den ich habe gelesen das...
Note that this is using a coma, not % (which would be a direct string substitution, not escaped). Don't do this:
Wenn ich ein Komma verwende bekomme ich immer die Fehlermeldung "You have an error in your SQl syntax"... Kann mir einer weiter helfen?

Diese Information mit dem '%' bzw ',' habe ich von hier

Gruß Tagiru
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Der Unterschied ist nicht das Komma, sondern dass es sich bei dem ersten deiner Aufrufe um zwei Parameter handelt und nicht um einen (wie mittels %). Der Unterschied ist, dass mittels % der Inhalt deines Tupels blind in den Ausdruck kopiert wird. Das liefert natürlich eine schöne Lücke für SQL-Injections. Verwendest du hingegen die erste Variante, so sorgt Python dafür, dass so etwas nicht passieren kann. Ein String mit einer beliebigen Anweisung wird also dann nicht einfach blind in das SQL-Statement kopiert, sondern als String welcher auch selbigen Typ hat. Etwas mehr dazu findes du in PEP 249.

Nun zu deinem eigentlichen Problem: Es hängt von der Datenbank ab, bzw. von dem dazugehörigen Python-Wrapper, welche Notation du im SQL-Statement verwenden kannst. Bei einigen ist es %s, bei anderen ? und hinzu kommen noch einige Varianten. In dem Von mir verlinkten PEP sind alle Möglichkeiten aufgelistet. Du musst also die zu deiner Datenbank passende Notation auswählen.

Edit: Und zeige doch bei deinem nächsten Problem bitte die gesamte Fehlermeldun inklusive Traceback. Du magst damit noch nicht viel anfangen können, für die Helfenden ist das jedoch recht nützlich.

Sebastian
Das Leben ist wie ein Tennisball.
TagiruAkashi
User
Beiträge: 12
Registriert: Dienstag 31. Januar 2012, 18:58

Vielen Dank für die Informationen ;)

Ich verwende MySQL + MySQLdb. Ein...

Code: Alles auswählen

print MySQLdb.paramstyle
liefert mir ''format". Damit wäre %s schon einmal die richtige Wahl. Leider bekomme ich weiterhin den Fehler...gegenwärtig an folgendem Beispiel.

Code: Alles auswählen

self.__database = {
                      'host' : "localhost",
                      'user' : "root",
                      'pass' : "1234",
                      'db'   : "test",
        }   

Code: Alles auswählen

cursor.execute("""CREATE DATABASE IF NOT EXISTS %s""", (self.__database['db'],))
Der Traceback...
Traceback (most recent call last):
File "C:\Temp\Python\2.7.2\Scripts\paster-script.py", line 9, in <module>
load_entry_point('pastescript==1.7.5', 'console_scripts', 'paster')()
File "C:\Temp\Python\2.7.2\lib\site-packages\pastescript-1.7.5-py2.7.egg\paste\script\command.py", line 104, in run
invoke(command, command_name, options, args[1:])
File "C:\Temp\Python\2.7.2\lib\site-packages\pastescript-1.7.5-py2.7.egg\paste\script\command.py", line 143, in invoke
exit_code = runner.run(args)
File "C:\Temp\Python\2.7.2\lib\site-packages\pastescript-1.7.5-py2.7.egg\paste\script\command.py", line 238, in run
result = self.command()
File "C:\Temp\Python\2.7.2\lib\site-packages\pastescript-1.7.5-py2.7.egg\paste\script\serve.py", line 284, in command
relative_to=base, global_conf=vars)
File "C:\Temp\Python\2.7.2\lib\site-packages\pastescript-1.7.5-py2.7.egg\paste\script\serve.py", line 321, in loadapp
**kw)
File "C:\Temp\Python\2.7.2\lib\site-packages\pastedeploy-1.5.0-py2.7.egg\paste\deploy\loadwsgi.py", line 247, in loadapp
return loadobj(APP, uri, name=name, **kw)
File "C:\Temp\Python\2.7.2\lib\site-packages\pastedeploy-1.5.0-py2.7.egg\paste\deploy\loadwsgi.py", line 272, in loadobj
return context.create()
File "C:\Temp\Python\2.7.2\lib\site-packages\pastedeploy-1.5.0-py2.7.egg\paste\deploy\loadwsgi.py", line 710, in create
return self.object_type.invoke(self)
File "C:\Temp\Python\2.7.2\lib\site-packages\pastedeploy-1.5.0-py2.7.egg\paste\deploy\loadwsgi.py", line 146, in invoke
return fix_call(context.object, context.global_conf, **context.local_conf)
File "C:\Temp\Python\2.7.2\lib\site-packages\pastedeploy-1.5.0-py2.7.egg\paste\deploy\util.py", line 56, in fix_call
val = callable(*args, **kw)
File "C:\Users\User\Documents\Workspace\test\test\config\middleware.py", line 37, in make_app
config = load_environment(global_conf, app_conf)
File "C:\Users\User\Documents\Workspace\test\test\config\environment.py", line 31, in load_environment
config['pylons.app_globals'] = app_globals.Globals(config)
File "C:\Users\User\Documents\Workspace\test\test\lib\app_globals.py", line 23, in __init__
self.pi = Pipeline()
File "C:\Users\User\Documents\Workspace\test\core\pipeline.py", line 37, in __init__
self.__mysql = MYSQLCommunicator()
File "C:\Users\User\Documents\Workspace\test\core\mysqlcommunicator.py", line 47, in __init__
self.__create_database()
File "C:\Users\User\Documents\Workspace\test\core\mysqlcommunicator.py", line 67, in __create_database
cursor.execute("""CREATE DATABASE IF NOT EXISTS %s""", (self.__database['db'],))
File "C:\Temp\Python\2.7.2\lib\site-packages\MySQLdb\cursors.py", line 174, in execute
self.errorhandler(self, exc, value)
File "C:\Temp\Python\2.7.2\lib\site-packages\MySQLdb\connections.py", line 36, in defaulterrorhandler
raise errorclass, errorvalue
_mysql_exceptions.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right s
yntax to use near ''test'' at line 1")
Eine Idee an was es liegen könnte?

Gruß Tagiru
BlackJack

@TagiruAkashi: Das dürfte daran liegen, dass man auf diese Weise nur *Werte* in SQL einfügen kann, aber keine Tabellennamen oder andere Syntax. Tabellennamen sollten aber in der Regel sowieso nicht aus Daten erstellt werden, die von Benutzern eingegeben werden. Das kommt eigentlich nur bei Programmen vor, mit denen man beliebige Datenbanken manipulieren können will. Normalerweise werden die Tabellen und Beziehungen für ein Programm in einem Datenbankentwurf einmal festgelegt und es kommen nicht dynamisch Tabellen hinzu.
TagiruAkashi
User
Beiträge: 12
Registriert: Dienstag 31. Januar 2012, 18:58

In diesem Fall war es so das es einfach darum ging, das wenn man den Datenbanknamen ändern möchte, hierfür nur an einer Stelle Hand anlegt werden muss. Den dieser wird noch an 2-3 anderen Stellen verwendet wie zum Beispiel für "use xyz" und "drop xyz".

Unabhängig davon scheint es aber nicht daran zu liegen den in einer anderen Zeile tritt das selbe Problem auf.

Code: Alles auswählen

sFolder="test"
cursor.execute("""SELECT sid FROM pyc_system WHERE system='%s'""" , (sFolder),)
Und das sollte doch gehen oder?

Traceback...
Traceback (most recent call last):
File "C:\Temp\Python\2.7.2\Scripts\paster-script.py", line 9, in <module>
load_entry_point('pastescript==1.7.5', 'console_scripts', 'paster')()
File "C:\Temp\Python\2.7.2\lib\site-packages\pastescript-1.7.5-py2.7.egg\paste\script\command.py", line 104, in run
invoke(command, command_name, options, args[1:])
File "C:\Temp\Python\2.7.2\lib\site-packages\pastescript-1.7.5-py2.7.egg\paste\script\command.py", line 143, in invoke
exit_code = runner.run(args)
File "C:\Temp\Python\2.7.2\lib\site-packages\pastescript-1.7.5-py2.7.egg\paste\script\command.py", line 238, in run
result = self.command()
File "C:\Temp\Python\2.7.2\lib\site-packages\pastescript-1.7.5-py2.7.egg\paste\script\serve.py", line 284, in command
relative_to=base, global_conf=vars)
File "C:\Temp\Python\2.7.2\lib\site-packages\pastescript-1.7.5-py2.7.egg\paste\script\serve.py", line 321, in loadapp
**kw)
File "C:\Temp\Python\2.7.2\lib\site-packages\pastedeploy-1.5.0-py2.7.egg\paste\deploy\loadwsgi.py", line 247, in loadapp
return loadobj(APP, uri, name=name, **kw)
File "C:\Temp\Python\2.7.2\lib\site-packages\pastedeploy-1.5.0-py2.7.egg\paste\deploy\loadwsgi.py", line 272, in loadobj
return context.create()
File "C:\Temp\Python\2.7.2\lib\site-packages\pastedeploy-1.5.0-py2.7.egg\paste\deploy\loadwsgi.py", line 710, in create
return self.object_type.invoke(self)
File "C:\Temp\Python\2.7.2\lib\site-packages\pastedeploy-1.5.0-py2.7.egg\paste\deploy\loadwsgi.py", line 146, in invoke
return fix_call(context.object, context.global_conf, **context.local_conf)
File "C:\Temp\Python\2.7.2\lib\site-packages\pastedeploy-1.5.0-py2.7.egg\paste\deploy\util.py", line 56, in fix_call
val = callable(*args, **kw)
File "C:\Users\TimoS\Documents\Workspace\pycodi\pycodi\config\middleware.py", line 37, in make_app
config = load_environment(global_conf, app_conf)
File "C:\Users\TimoS\Documents\Workspace\pycodi\pycodi\config\environment.py", line 31, in load_environment
config['pylons.app_globals'] = app_globals.Globals(config)
File "C:\Users\TimoS\Documents\Workspace\pycodi\pycodi\lib\app_globals.py", line 23, in __init__
self.pi = Pipeline()
File "C:\Users\TimoS\Documents\Workspace\pycodi\core\pipeline.py", line 37, in __init__
self.__mysql = MYSQLCommunicator()
File "C:\Users\TimoS\Documents\Workspace\pycodi\core\mysqlcommunicator.py", line 47, in __init__
self.__evaluate_systems()
File "C:\Users\TimoS\Documents\Workspace\pycodi\core\mysqlcommunicator.py", line 155, in __evaluate_systems
cursor.execute("""SELECT sid FROM pyc_system WHERE system='%s'""" , (sFolder),)
File "C:\Temp\Python\2.7.2\lib\site-packages\MySQLdb\cursors.py", line 174, in execute
self.errorhandler(self, exc, value)
File "C:\Temp\Python\2.7.2\lib\site-packages\MySQLdb\connections.py", line 36, in defaulterrorhandler
raise errorclass, errorvalue
_mysql_exceptions.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right s
yntax to use near 'test''' at line 1")
Gruß Tagiru
BlackJack

@TagiruAkashi: Nein das ist falsch. Du darfst nicht selbst versuchen den Wert zu „schützen”, da darf einfach nur der Platzhalter stehen. Wenn es notwendig ist eine Zeichenkette zum Beispiel durch einzelne Anführungsstriche zu als solche zu kennzeichnen, dann macht das `execute()`. Einige Datenbanken/Anbindungen erstellen auch gar nicht eine SQL-Anweisung mit dem Wert, sondern übermitteln beides getrennt. Mit dem Vorteil dass die SQL-Anweisung mit dem Platzhalter nur einmal in einen effizienten Ablaufplan für die Abfrageabarbeitung übersetzt werden muss, und für weitere Abfragen gecachet werden kann. Dann müssen bei folgenden Abfragen nur die Werte übertragen werden.
TagiruAkashi
User
Beiträge: 12
Registriert: Dienstag 31. Januar 2012, 18:58

Danke es funktioniert ;)
Antworten