Python remove the single quotes from the dictionary - python

I have following PostgreSQL query
data = {'token':"123",'kart_user':"tablename"}
select_stmt = "SELECT * FROM %(kart_user)s WHERE token = %(token)s"
self.cur.execute(select_stmt, data)
result = self.cur.fetchone()
In the select query %(kart_user)s is represent in the form of single quotes
My question is how can i remove the quotes from the same query??.

The whole point of using SQL parameters is to prevent data being interpreted as SQL objects or syntax. You can't use SQL parameters to name tables; you can only use SQL parameters for data.
You'll have to interpolate table names separately. This does means you run a risk of opening up your code to SQL injections; I'd test the table name against a list of known tablenames if this is sourced from user input.
assert data['kart_user'] in known_tables
select_stmt = "SELECT * FROM {} WHERE token = %(token)s".format(data['kart_user'])
self.cur.execute(select_stmt, data)

Related

How to avoid SQL Injection in Python for Upsert Query to SQL Server?

I have a sql query I'm executing that I'm passing variables into. In the current context I'm passing the parameter values in as f strings, but this query is vulnerable to sql injection. I know there is a method to use a stored procedure and restrict permissions on the user executing the query. But is there a way to avoid having to go the stored procedure route and perhaps modify this function to be secure against SQL Injection?
I have the below query created to execute within a python app.
def sql_gen(tv, kv, join_kv, col_inst, val_inst, val_upd):
sqlstmt = f"""
IF NOT EXISTS (
SELECT *
FROM {tv}
WHERE {kv} = {join_kv}
)
INSERT {tv} (
{col_inst}
)
VALUES (
{val_inst}
)
ELSE
UPDATE {tv}
SET {val_upd}
WHERE {kv} = {join_kv};
"""
engine = create_engine(f"mssql+pymssql://{username}:{password}#{server}/{database}")
connection = engine.raw_connection()
cursor = connection.cursor()
cursor.execute(sqlstmt)
connection.commit()
cursor.close()
Fortunately, most database connectors have query parameters in which you pass the variable instead of giving in the string inside the query yourself for the risks you mentioned.
You can read more on this here: https://realpython.com/prevent-python-sql-injection/#understanding-python-sql-injection
Example:
# Vulnerable
cursor.execute("SELECT admin FROM users WHERE username = '" + username + '");
# Safe
cursor.execute("SELECT admin FROM users WHERE username = %s'", (username, ));
As Amanzer mentions correctly in his reply Python has mechanisms to pass parameters safely.
However, there are other elements in your query (table names and column names) that are not supported as parameters (bind variables) because JDBC does not support those.
If these are from an untrusted source (or may be in the future) you should be sure you validate these elements. This is a good coding practice to do even if you are sure.
There are some options to do this safely:
You should limit your tables and columns based on positive validation - make sure that the only values allowed are the ones that are authorized
If that's not possible (because these are user created?):
You should make sure tables or column names limit the
names to use a "safe" set of characters (alphanumeric & dashes,
underscores...)
You should enquote the table names / column names -
adding double quotes around the objects. If you do this, you need to
be careful to validate there are no quotes in the name, and error out
or escape the quotes. You also need to be aware that adding quotes
will make the name case sensitive.

Passing parameters to LIKE SQL query

I want to pass dynamic parameter to the LIKE query using Fast API (Python) coming from the query parameter. I have tried a lot of ways but I don't know what I am doing wrong.
The query I need to use is :
SELECT Time, table_id, Text FROM tablename WHERE Text LIKE '%text%'
The python code for getting query parameter is :
def get_result(text : str):
con = connection.connect()
statement = 'SELECT Time, table_id, Text FROM tablename WHERE Text LIKE '%text%''
How will I pass the dynamic text parameter in this query because this gives the error saying "TypeError: not all arguments converted during string formatting"?
You cannot nest single quotes. Also, it's clearer to use a f-string for string formatting here. Try:
statement = f"SELECT Time, table_id, Text FROM tablename WHERE Text LIKE '%{text}%'"
NEVER substitute values directly in to a SQL string like that. EVER. Use parameterised queries / bind variables.
For example, depending on the driver/library you're using, you may be able to use...
con = connection.connect()
cur = con.cursor()
cur.execute("SELECT Time, table_id, Text FROM tablename WHERE Text LIKE %s", ('%' + text + '%',))

Fetch one row from MySQL table

I'm trying to fetch one row of a MySQL table based on a user input. My code is:
"""Get entry information"""
reinforcement_name = reinforcement_input.get()
"""Fetch reinforcement data"""
mycursor = mydb.cursor()
sql_select_query = "select '*' from reinforcement where name = '%s'"
mycursor.execute(sql_select_query, reinforcement_name)
reinforcement_data = mycursor.fetchone()
print(reinforcement_data)
I'm expecting to get a list of column entries for that specific user input. However, I'm getting None printed out rather than a list.
How can I have my reinforcement_data presented as the list I'm expecting?
The fetchone call is OK. The problem is with your query - when you use a parameterized query, you should not use quotes around the bind variables - these aren't simple string replacements, but bind variables the database driver handles. Here, you're querying for a row with the literal name of %s, which probably doesn't exist. The parameters need to pass to execute as an iterable.
On a related note, you should also remove the quotes around the * in the select list, otherwise, you'll get the asterisk literal, not all the columns.
sql_select_query = "select * from reinforcement where name = %s"
# No quotes --------------^-^-------------------------------^--^
mycursor.execute(sql_select_query, (reinforcement_name,))
# Params passed as a tuple --------^

How to insert date mysql python telegrambot

I always failled to insert data to Mysql database from my telegram bot, and always run Exception. Only tanggald allways failed to insert. I thing format of date insert query is wrong. How to write correct format?
tanggald column detail : Data Type = DATE
This is piece of code:
def process_lanjut(message):
try:
chat_id = message.chat.id
qlanjut = message.text
user = user_dict[chat_id]
user.qlanjut=qlanjut
d = datetime.datetime.now().date()
next_monday = next_weekday(d, 4)
user.next_monday = next_monday
print(user.next_monday)
with con.cursor() as cursor:
sql = "INSERT INTO diagnosa(sex, tanggald) VALUES('" + user.sex + "','" +next_monday+ "')"
cursor.execute(sql)
con.commit()
con.close()
msg = bot.send_message(chat_id, 'thanks')
bot.register_next_step_handler(msg, send_end)
except Exception as e:
bot.reply_to(message,'oops lanjut')
On command line output : 2018-04-20 (data that should be INSERT to tanggald)
That's not the proper way to insert data into table. Although your way may work, it is not safe and it lacks data escaping (', ", etc.):
The SQL representation of many data types is often different from their Python string representation. The typical example is with single quotes in strings: in SQL single quotes are used as string literal delimiters, so the ones appearing inside the string itself must be escaped, whereas in Python single quotes can be left unescaped if the string is delimited by double quotes.
Because of the difference, sometime subtle, between the data types representations, a naïve approach to query strings composition, such as using Python strings concatenation, is a recipe for terrible problems.
If the variables containing the data to send to the database come from an untrusted source (such as a form published on a web site) an attacker could easily craft a malformed string, either gaining access to unauthorized data or performing destructive operations on the database. This form of attack is called SQL injection and is known to be one of the most widespread forms of attack to database servers. Before continuing, please print this page as a memo and hang it onto your desk.
So in your case the INSERT statement should look like this:
with con.cursor() as cursor:
sql = 'INSERT INTO diagnosa (sex, tanggald) VALUES (%s, %s)'
data = (user.sex, next_monday)
cursor.execute(sql, data)
Further reading:
MySQL docs and example
Similar article for PostgreSQL (contains a better explanation of potential problems)

Creating Insert Statement for MySQL in Python

I am trying to construct an insert statement that is built from the results of a query. I run a query that retrieves results from one database and then creates an insert statement from the results and inserts that into a different database.
The server that is initially queried only returns those fields in the reply which are populated and this can differ from record to record. The destination database table has all of the possible fields available. This is why I need to construct the insert statement on the fly for each record that is retrieved and why I cannot use a default list of fields as I have no control over which ones will be populated in the response.
Here is a sample of the code, I send off a request for the T&C for an isin and the response is a name and value.
fields = []
data = []
getTCQ = ("MDH:T&C|"+isin+"|NAME|VALUE")
mdh.execute(getTCQ)
TC = mdh.fetchall()
for values in TC:
fields.append(values[0])
data.append(values[1])
insertQ = ("INSERT INTO sp_fields ("+fields+") VALUES ('"+data+"')")
The problem is with the fields part, mysql is expecting the following:
INSERT INTO sp_fields (ACCRUAL_COUNT,AMOUNT_OUTSTANDING_CALC_DATE) VALUES ('030/360','2014-11-10')
But I am getting the following for insertQ:
INSERT INTO sp_fields ('ACCRUAL_COUNT','AMOUNT_OUTSTANDING_CALC_DATE') VALUES ('030/360','2014-11-10')
and mysql does not like the ' ' around the fields names.
How do I get rid of these? so that it looks like the 1st insertQ statement that works.
many thanks in advance.
You could use ','.join(fields) to create the desired string (without quotes around each field).
Then use parametrized sql and pass the values as the second argument to cursor.execute:
insertQ = ("INSERT INTO sp_fields ({}) VALUES ({})".format(
','.join(fields), ','.join(['%s']*len(dates)))
cursor.execute(insertQ, dates)
Note that the correct placemarker to use, e.g. %s, depends on the DB adapter you are using. MySQLdb uses %s, but oursql uses ?, for instance.

Categories