tags:

views:

1102

answers:

2

I know how to map a list to a string:

foostring = ",".join( map(str, list_of_ids) )

And I know that I can use the following to get that string into an IN clause:

cursor.execute("DELETE FROM foo.bar WHERE baz IN ('%s')" % (foostring))

What I need is to accomplish the same thing SAFELY (avoiding SQL injection) using MySQLDB. In the above example because foostring is not passed as an argument to execute, it is vulnerable. I also have to quote and escape outside of the mysql library.

(There is a related SO question, but the answers listed there either do not work for MySQLDB or are vulnerable to SQL injection.)

+12  A: 

Use the list_of_ids directly:

format_strings = ','.join(['%s'] * len(list_of_ids))
cursor.execute("DELETE FROM foo.bar WHERE baz IN (%s)" % format_strings,
                tuple(list_of_ids))

That way you avoid having to quote yourself, and avoid all kinds of sql injection.

Note that the data (list_of_ids) is going directly to mysql's driver, as a parameter (not in the query text) so there is no injection. You can leave any chars you want in the string, no need to remove or quote chars.

nosklo
Why quote the %s in the format_strings? Won't this be handled by the .execute() method, too?
unbeknown
@heikogerlach: I am not quoting the %s... The first line creates a string of "%s,%s,%s"... the same size of list_of_ids length.
nosklo
Argh, you're right. Need to look harder. Somehow I mixed it up. Nice solution, though.
unbeknown
A: 

Did somebody take a look on MySQLdb source code? If not I suggest you to look at it - mainly because MySQLdb create the query on the client side and doesn't pass parameters to the server!

So it doesn't matter how you use it your code is vulnerable!

Really? That must suck. Let me check... (checks) ... huh, not really - `.execute()` method actually passes the argument list through an encoder http://mysql-python.svn.sourceforge.net/viewvc/mysql-python/trunk/MySQLdb/MySQLdb/converters.py?view=markup so you're safe. It sucks that the mysql server itself doesn't do that, but that is a mysql driver detail - you shouldn't do the interpolation yourself anyway, if you change drivers things can be different under the hood.
nosklo