OperationalError: no such column: XX - Sqlite - python

I'm using sqlite3 alongside python. I'm just trying to get some really basic auth going on but when my sql query gets executed I am getting the following error:
OperationalError: no such column: admin
My query looks like the following:
cur.execute("SELECT * FROM users WHERE username=%s AND password=%s;" % (username, password))
Any ideas? I have searched around but can't find anything

You should never use string interpolation in database queries; as well as the problem you're having, you leave yourself open to SQL injection attacks. Instead, use the parameter substitution provided by the db api.
cur.execute("SELECT * FROM users WHERE username=? AND password=?", (username, password))

Related

How to do I use %s in a mysql query without errors

I am having some trouble selecting from my database using python to execute a MySql query. I have tried two methods to achieve this, but both methods have returned the error shown below:
mysql.connector.errors.ProgrammingError: 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '%s' at line 1
What Id like to do is return the row count (which is always zero or one) when a username parameter is passed. I have looked at other examples where people have had this issue but I cant find a good fix.
The first method I tried was this:
def check_data(username):
sql = """SELECT count(*) FROM tbl_user WHERE username = %s"""
mycursor.execute(sql, username)
#do something with the data
I then tried using SELECT (CASE WHEN (uname = %s) THEN TRUE ELSE FALSE END) AS IsEmtpy FROM tbl_user limit 1;
This works database side, but still throws the same error when run in the application. I tried wrapping the %s like '%s' but it didn't help.
Any suggestions?
You're missing enclosing the string between quotes (singles or doubles).
You can check the query you're executing by printing it before the mycursor.execute statement, but basically you're sending MySQL something like SELECT count(*) FROM tbl_user WHERE username = foobar.
Try fixing it with SELECT count(*) FROM tbl_user WHERE username = '%s'.
On a side note, your approach is vulnerable to SQL Injection. You should check the documentation of the tool you're using to connect to the DBMS for "prepared statements".

python pyodbc SQLite sql injections

I use pyodbc in my python flask Project for the SQLite DB connection.
I know and understand SQL Injections but this is my first time dealing with it.
I tried to execute some
I have a function which concatenates the SQL String in my database.py file:
def open_issue(self, data_object):
cursor = self.conn.cursor()
# data_object is the issue i get from the user
name = data_object["name"]
text = data_object["text"]
rating_sum = 0
# if the user provides an issue
if name:
# check if issue is already in db
test = cursor.execute(f'''SELECT name FROM issue WHERE name = "{name}"''')
data = test.fetchall()
# if not in db insert
if len(data) == 0:
# insert the issue
cursor.executescript(f'''INSERT INTO issue (name, text, rating_sum)
VALUES ("{name}", "{text}", {rating_sum})''')
else:
print("nothing inserted!")
In the api.py file the open_issue() function gets called:
#self.app.route('/open_issue')
def insertdata():
# data sent from client
# data_object = flask.request.json
# unit test dictionary
data_object = {"name": "injection-test-table",
"text": "'; CREATE TABLE 'injected_table-1337';--"}
DB().open_issue(data_object)
The "'; CREATE TABLE 'injected_table-1337';--" sql injection has not created the injected_table-1337, instead it got inserted normally like a string into the text column of the injection-test-table.
So i don't really know if i am safe for the standard ways of SQL injection (this project will only be hosted locally but good security is always welcome)
And secondary: are there ways with pyodbc to check if a string contains sql syntax or symbols, so that nothing will get inserted in my example or do i need to check the strings manually?
Thanks a lot
As it turns out, with SQLite you are at much less risk of SQL injection issues because by default neither Python's built-in sqlite3 module nor the SQLite ODBC driver allow multiple statements to be executed in a single .execute call (commonly known as an "anonymous code block"). This code:
thing = "'; CREATE TABLE bobby (id int primary key); --"
sql = f"SELECT * FROM table1 WHERE txt='{thing}'"
crsr.execute(sql)
throws this for sqlite3
sqlite3.Warning: You can only execute one statement at a time.
and this for SQLite ODBC
pyodbc.Error: ('HY000', '[HY000] only one SQL statement allowed (-1) (SQLExecDirectW)')
Still, you should follow best practices and use a proper parameterized query
thing = "'; CREATE TABLE bobby (id int primary key); --"
sql = "SELECT * FROM table1 WHERE txt=?"
crsr.execute(sql, (thing, ))
because this will also correctly handle parameter values that would cause errors if injected directly, e.g.,
thing = "it's good to avoid SQL injection"

Heroku Database: Insert operation

I am confused while inserting data to my Postgres Database in heroku.
Here's the thing,
I have created connection to database, then
cursor = conn.cursor()
cursor.execute("INSERT INTO users(username, useremail, userpass) VALUES ('"+_name+"','"+_email+"','"+_password+"')")
After executing, I checked the sql status by
print(cursor.statusmessage)
it returns,
INSERT 0 1
but on executing, data =
cursor.fetchall()
it throws me error
File "/Users/abc/PycharmProjects/testSkillNetwork/app.py",
line 75, in signUp
data = cursor.fetchall().
ProgrammingError: no results to fetch
So, i am unable to understand why 'no results' when insertion is successful.
Any help will be appreciated. Thanks.
You need to issue a SELECT query in order to retrieve data from the database.
cursor.execute("SELECT * FROM users")
cursor.fetchall()
This should give you some results.
Also, you should commit the transaction once you have finished inserting data, otherwise it will be lost. Use:
conn.commit()
Another, bigger, issue is that the way that you construct your queries is vulnerable to SQL injection. Rather than using string concatenation you should use parameterised queries:
cursor.execute("INSERT INTO users(username, useremail, userpass) VALUES (%s, %s, %s)", (_name,_email,_password))
With this style the database adapter will substitute the place holders (%s) with the values from the tuple of arguments passed to cursor.execute(). Not only is this safer, it's a lot easier to read and maintain.
I am not sure what driver are you using to connect to the database, assuming you're using psycopg2, which is one of the most famous, what you're observing is a normal behaviour. Reading from here:
A ProgrammingError is raised if the previous call to execute*() did not produce any result set or no call was issued yet.
An insert statement produces no result, other that an error in case of failure. If you want to obtain the rows that you've just inserted, query the database again:
cur.execute("SELECT * FROM users;")
cur.fetchall()
and this will give you the rows.
Aside from this, if you read the basic usage and the section of parametrized queries, never use python string concatenation when executing your queries, because it makes it vulnerable to SQL injection attacks.

Avoiding SQL injection in Flask SQL Alchemy

I want to take the username from a login field after submission to query my SQL Alchemy database. In the past I used things like the following:
rows = db.execute("SELECT * FROM users WHERE username = :username", username=request.form.get("username"))
However this was in CS50 and I am now using SQL Alchemy and want to know how to use a similar ":username" statement. So far this is all I have:
userinfo = User.query.filter_by(username= :username).first(), username=request.form.get("username")
This does not work. I am using the documentation found here http://flask-sqlalchemy.pocoo.org/2.1/queries/ to help write this statement. I am getting an error for invalid syntax. The User class is set up like the "simple example" from http://flask-sqlalchemy.pocoo.org/2.1/models/#models but does not have the repr function.

Tornado: get_argument -- should I escape the input myself?

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.

Categories

Resources