Prevent MySQL-Python from inserting quotes around database name parameter - python

I'm working on a project that requires me to programmatically create MySQL users from a django app. I can create the users just fine:
from django.db import connection, transaction
cursor = connection.cursor()
cursor.execute("CREATE USER %s#'%'", 'username')
cursor.execute("SET PASSWORD FOR %s#'%' = PASSWORD(%s)", ('username', 'pass'))
That works perfectly. The problem is when I try to grant permissions. The database name is also determined programmatically:
cursor.execute("GRANT SELECT ON %s.* TO %s#'%'", ('dbname', 'username'))
This results in a mysql error because when it does the string substitution, it places single quotes around the database name, which is syntactically incorrect:
DatabaseError: (1064, "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 ''dbname'.* to 'username'#'%'' at line 1")
How do I prevent the single quotes from being added around the %s for database name? I know that I could simply do the string substitution in Python and fix this, but that could potentially cause a SQL injection vulnerability.

Sometimes placeholders won't work (as you've found out), so you'll have to use string concatenation. Be careful - validate the string, make sure it's only composed of the characters you expect (don't just look for characters you don't expect), and you should be OK. Also get another developer to check your code, and comment it to make sure no-one else thinks you ought to be using placeholders.

Related

pymysql.err.ProgrammingError 1064 in simple multiline SQL query for mariadb

I have tried everything and keep getting this error:
pymysql.err.ProgrammingError: (1064, "You have an error in your SQL syntax;
check the manual that corresponds to your MariaDB server version for the right syntax to use near
'INSERT INTO tabSingles (doctype, field, value) VALUES ('Bank Reconciliation', 'a' at line 2")
Expanded query (after python format expansion):
SELECT value INTO #var FROM tabSingles WHERE doctype = 'Bank Reconciliation' AND field = 'bank_account';
INSERT INTO tabSingles (doctype, field, value) VALUES ('Bank Reconciliation', 'account', #var);
DELETE FROM tabSingles WHERE doctype = 'Bank Reconciliation' AND field = 'bank_account';
Can anyone see the problem? Is there some issue with multi-line queries? I have tried the individual lines on the mariadb command line and they appear to work as expected. I've also tried both frappe.db.sql and multisql (thought it meant multiline sql but doesn't). If I comment line 2 out, it also errors on line 3. Sorry to disturb but I've been staring at this for hours and cannot figure it out!
EDIT:
The obvious answer is this, but I'd still like to know why it doesn't like the original query:
UPDATE tabSingles SET field='{new_name}' WHERE doctype='{doctype}' AND field='{old_name}';
For security reasons (mainly SQL injection) MariaDB (and MySQL) servers don't support the execution of multiple SQL statements by default.
For supporting multiple statements execution the client needs to send COM_SET_OPTION command and MYSQL_OPTION_MULTI_STATEMENTS_ON flag to the server, which is not supported by PyMySQL.
Do not try to run more than one statement in a call.
Do use BEGIN and COMMIT.
Do use FOR UPDATE.
You need 5 separate commands:
BEGIN;
SELECT ... FOR UPDATE; -- to keep other connections from messing with the row(s).
UPDATE ...;
DELETE ...
COMMIT; -- do all of the above "atomically"

How to execute SQL verbatim?

I have the following code:
db.execute(sql)
sql contains the character sequence %s. This makes SQLAlchemy raise an exception because I don't provide any parameters. Is it possible to make SQLAlchemy pass sql verbatim to the database without trying to substitute any parameters, so that the database also receives the character sequence %s?
Disclaimer: I am totally aware of how SQL injection works and I know what I'm doing; this isn't an issue.
Use sqlalchemy.text:
db.execute(sqlalchemy.text(sql))

How to insert unicode string to mysql

the code is like below:
Connect server
MySQLdb.connect(host=ip, user='root', passwd='root',db='test',use_unicode=True,charset="utf8")
......
sql = "INSERT INTO ci(id,name) VALUES (493,u'Hello')"
print sql
ret = root.execute(sql)
.....
In the server, the tyoe of name is VARCHAR(1000). Then when i run this script, it shows error ProgrammingError: (1064, "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
But when i replace u'Hello' with 'Hello', it is OK. So maybe it doesn't support unicode,then i insert unicode string such as "你好" to the table by GUI manually, it is also OK. I can not find what is the reason, who can help me
MySQL needs strings to be enclosed in straight quotes: '你好', 'u' symbol is not allowed. Just declare the whole string as Unicode and pass it to MySQL. Here I am using a prepared statement:
sql = u"INSERT INTO ci(id,name) VALUES (493,'你好')"
Don't forget to run "SET NAMES 'UTF-8'" (or UTF-16 - don't know, what encoding you are using) after you connect to MySQL to ensure, that the server will correctly interpret the string you send it.

Strange SQL statement error in SQLAlchemy-Flask

I am using SQLAlchemy in Flask to connect to my Postgres server, and now I want to execute some raw SQL to insert a column into a table. I am getting this error, however:
sqlalchemy.exc.ProgrammingError: (ProgrammingError) syntax error at or near "user"
LINE 1: ALTER TABLE user ADD COLUMN permissions INTEGER
^
'ALTER TABLE user ADD COLUMN permissions INTEGER' {}
As you can see, it says there is an SQL error, although I have no idea what I could be doing wrong.
This is the very simple function that executes the command:
#staticmethod
def addColumn():
db.engine.execute('ALTER TABLE user ADD COLUMN permissions INTEGER')
The db object otherwise works perfectly, and there is nothing wrong with the connection or anything of the sort.
I feel like I'm overlooking something very simple, but I just can't figure out what it is. Does anybody have any idea?
The PostgreSQL docs say that USER is a reserved keyword, and needs to be quoted to be used as an identifier.
Key Word PostgreSQL SQL 99 SQL 92
USER reserved reserved reserved
Is user a reserved word and thus needing to be referenced specially in SQL statement?

MySQLdb input where strings contain string delimiters

I'm working on a project in Python with MySQLdb. As part of this, I'm moving user details, including salted passwords from one system that generates them to a new one that simply uses them.
Single, double or triple quotes can delineate your string start and end. However, single and double quotes are part of several hashes in the 4.5k or so users I'm migrating. Both tokens appear in about 450 of those salts.
An edited version of the code is as follows
Django.execute ('INSERT INTO auth_user (password) VALUES ("' + user.password + '")')
I have tried swapping between the quote type used in this database cursor object, as and when either quote type or the other are detected, but this still leaves the 150 or so that contain both.
What work arounds can I use for this?
I have tried triple quotes, but they throw a programming error on the cursor object.
Thanks in advance
Query parameters should provide all the proper escaping, for example:
cursor.execute('INSERT INTO auth_user (password) VALUES (%s)', [password])
From the Django docs at: http://docs.djangoproject.com/en/dev/topics/db/sql/
If you're not familiar with
the Python DB-API, note that the SQL
statement in cursor.execute() uses
placeholders, "%s", rather than adding
parameters directly within the SQL. If
you use this technique, the underlying
database library will automatically
add quotes and escaping to your
parameter(s) as necessary. (Also note
that Django expects the "%s"
placeholder, not the "?" placeholder,
which is used by the SQLite Python
bindings. This is for the sake of
consistency and sanity.)

Categories