I'm running a Tornado web server for a single page application. The client is POSTing to the server and I'm using tornado.web.RequestHandler.get_argument()
to get the input.
When testing, I can't seem to force an SQL injection bug. It looks like get_argument()
somehow escapes the input. When doing a POST from a login-form (username + password) I've tried all sorts of tricks to force a simple SQL injection but to no avail.
EDIT2:
HAH! I managed to do an SQL injection at last :D I URL-escaped some of the input and I could see the injected SQL statement go all the way to the DB module. The query I generate from the login-form does not get committed, as it's just supposed to be a SELECT statement - so I couldn't actually alter the database.
If the query never gets committed and the output of the whole query (including the injected) is hidden, what kind of damage can be done ?
For instance if the query is supposed to be, say SELECT * FROM Users WHERE UserID='USERNAME' AND Password='PASSWORD';
but the input for username has an INSERT injected, so USERNAME
becomes USERNAME'; INSERT INTO Users (UserID, Password) VALUES ('hacker', 'hacked'); --
we end up with:
SELECT * FROM Users WHERE UserID='USERNAME'; INSERT INTO Users (UserID, Password) VALUES ('hacker', 'hacked'); --' AND Password='PASSWORD';
I am aware of the dangers of SQL injections in general, I'm just curious regarding this detail. I'm also aware I should hash and salt passwords, the code above is a simplification for the sake of the example.
Tornado only escapes the strings in the templates to avoid HTML issues. If you're just doing something like print self.get_argument('ihack')
you'll get the raw string that is sent.
You should using MySQLdb with injection prevention:
cursor.execute("SELECT * FROM user_info WHERE email = %s", email)
Rather than:
cursor.execute("SELECT * FROM user_info WHERE email = %s" % email) # BAD!
This will protected your SQL just like the templates protect your HTML.