I have the following python code:
row = conn.execute('''SELECT admin FROM account WHERE password = ?''',
(request.headers.get('X-Admin-Pass'),)).fetchone()
My question is whether this code is secure for SQL injection? Since I use parameterized query it should be. However, since I am passing user information straight from the header, I am a little worried :)
Any thoughts about the issue?
The way that you are inserting the data into the database will ensure that an SQL attack will not work, the execute method will automatically escape the parameters that you passed as a tuple as its second parameter to the query.
You are doing that correctly.
If your module uses the DBI specs, then you're parameterizing fine. Unless you want to do research into preventing specific SQL attacks, paramterizing your queries is a good umbrella against SQL injection.
Related
I am working on accessing data in BigQuery with Python to do some data analysis. I access the data with a standard SQL query of:
"SELECT * FROM `project.dataset.table`"
I am using the same base code on multiple datasets so I took the approach of using environment variables for the project, dataset and table, giving me an actual query that looks like this:
f"SELECT * FROM `{PROJECT}.{DATASET}.{TABLE}`"
I did this in an effort to abstract my tables a little. I run bandit testing in my CI/CD pipeline and this query using variables is failing, suggesting possible injection. Now my query cannot be changed by user input as there are no points where I take user input to get to this query. I'm trying to figure out if this is a safe query to include in my code. I've attempted running more variables, less variables, using secret manager and all fail the bandit testing.
My gut is telling me that the usage of the variables "hides" some of my info since the table is at least separate from the query and that since no users can input anything there is no issue. But the failing test has me a bit concerned. Any thoughts on if this is safe?
SQL injection is important, because it allows the attacker to destroy and read sensitive data.
for your query you can: parameterized queries, Parameterized statements ensure that the parameters passed into the SQL statements are treated safely.
BigQuery supports query parameters to help prevent SQL injection when queries are constructed using user input. This feature is only available with standard SQL syntax.
#Example
client = bigquery.Client()
query = """
SELECT word, word_count
FROM `bigquery-public-data.samples.shakespeare`
WHERE corpus = #corpus
AND word_count >= #min_word_count
ORDER BY word_count DESC;
"""
job_config = bigquery.QueryJobConfig(
query_parameters=[
bigquery.ScalarQueryParameter("corpus", "STRING", "romeoandjuliet"),
bigquery.ScalarQueryParameter("min_word_count", "INT64", 250),
]
)
query_job = client.query(query, job_config=job_config) # Make an API request.
google refrence
YES
since no users can input anything there is no issue
If an attacker gains access to your environment variables, they can use them to perform a SQL injection. This is privilege elevation or escalation.
Parameters normally don't work on identifiers such as table names, only values. You can still protect yourself by filtering the identifiers. Some libraries have a function to do this. At minimum, make sure they don't contain a `.
Consider using a SQL builder which will take care of this for you.
Sorry for ask here but I cannot found much reference about pymysql's security guide about how do we prevent sql injection,
When I do PHP develope I know use mysql preparedstatement(or called Parameterized Query or stmt),but I cannot found reference about this in pymysql
simple code use pymysql like
sqls="select id from tables where name=%s"
attack="jason' and 1=1"
cursor.execute(sqls,attack)
How do I know this will prevent sql injection attack or not?if prevent succeed,how do pymysql prevent?Is cursor.execute already use preparedstatement by default?
Python drivers do not use real query parameters. In python, the argument (the variable attack in your example) is interpolated into the SQL string before sending the SQL to the database server.
This is not the same as using a query parameter. In a real parameterized query, the SQL string is sent to the database server with the parameter placeholder intact.
But the Python driver does properly escape the argument as it interpolates, which protects against SQL injection.
I can prove it when I turn on the query log:
mysql> SET GLOBAL general_log=ON;
And tail the log while I run the Python script:
$ tail -f /usr/local/var/mysql/bkarwin.log
...
180802 8:50:47 14 Connect root#localhost on test
14 Query SET ##session.autocommit = OFF
14 Query select id from tables where name='jason\' and 1=1'
14 Quit
You can see that the query has had the value interpolated into it, and the embedded quote character is preceded by a backslash, which prevents it from becoming an SQL injection vector.
I'm actually testing MySQL's Connector/Python, but pymysql does the same thing.
I disagree with this design decision for the Python connectors to avoid using real query parameters (i.e. real parameters work by sending the SQL query to the database with parameter placeholders, and sending the values for those parameters separately). The risk is that programmers will think that any string interpolation of parameters into the query string will work the same as it does when you let the driver do it.
Example of SQL injection vulnerability:
attack="jason' and '1'='1"
sqls="select id from tables where name='%s'" % attack
cursor.execute(sqls)
The log shows this has resulted in SQL injection:
180802 8:59:30 16 Connect root#localhost on test
16 Query SET ##session.autocommit = OFF
16 Query select id from tables where name='jason' and '1'='1'
16 Quit
I am new to using SQLite with python and we have been code in which there is this statement
c.execute('INSERT INTO users VALUES (?,?)', user)
I am not sure what the question marks (?,?) mean, I have tried reading the documentation on sqlite3 website but was not able to get anywhere. Would be a great help if someone can tell me or direct me to the right link.
Thank you
They are placeholders for literal values that can be bound to a prepared SQL statement. Essentially it allows you to supply literal values in the SQL program without putting them into the SQL string. This both prevents SQL injection attacks and improves performance if you're running the same query with different parameter values - the SQL has to be compiled only once.
Documentation (C API)
I'm working on a small app which will help browse the data generated by vim-logging, and I'd like to allow people to run arbitrary SQL queries against the datasets.
How can I do that safely?
For example, I'd like to let someone enter, say, SELECT file_type, count(*) FROM commands GROUP BY file_type, then send the result back to their web browser.
Do this:
cmd = "update people set name=%s where id=%s"
curs.execute(cmd, (name, id))
Note that the placeholder syntax depends on the database you are using.
Source and more info here:
http://bobby-tables.com/python.html
Allowing expressive power while preventing destruction is a difficult job. If you let them enter "SELECT .." themselves, you need to prevent them from entering "DELETE .." instead. You can require the statement to begin with "SELECT", but then you also have to be sure it doesn't contain "; DELETE" somewhere in the middle.
The safest thing to do might be to connect to the database with read-only user credentials.
In MySQL, you can create a limited user (create new user and grant limited access), which can only access certain table.
Consider using SQLAlchemy. While SQLAlchemy is arguably the greatest Object Relational Mapper ever, you certainly don't need to use any of the ORM stuff to take advantage of all of the great Python/SQL work that's been done.
As the introductory documentation suggests:
Most importantly, SQLAlchemy is not just an ORM. Its data abstraction layer allows construction and manipulation of SQL expressions in a platform agnostic way, and offers easy to use and superfast result objects, as well as table creation and schema reflection utilities. No object relational mapping whatsoever is involved until you import the orm package. Or use SQLAlchemy to write your own!
Using SQLAlchemy will give you input sanitation "for free" and let you use standard Python logic to analyze statements for safety without having to do any messy text-parsing/pattern-matching.
In diagnosing SQL query problems, it would sometimes be useful to be able to see the query string after parameters are interpolated into it, using MySQLdb's safe interpolation.
Is there a way to get that information from either a MySQL exception object or from the connection object itself?
Use mysql's own ability to log the queries and watch for them.
Perhaps You could use the slow_query_log?
If You cannot turn on the mysql's internal ability to log all queries, You need to write down all the queries before You execute them... You can store them in an own log-file, or in a table (or in some other system). If that would be the case, and if I were You, I'd create an wrapper for the connection with the logging ability.