mirror of
https://github.com/github/codeql.git
synced 2026-05-02 20:25:13 +02:00
Python: Don't quote %s in django example
This is vulnerable to SQL injection because of the quotes around %s -- added some code that highlights this in test.py Since our examples did this in the safe query, I ended up rewriting them completely, causing a lot of trouble for myself :D
This commit is contained in:
@@ -21,20 +21,29 @@ or prepared statements.
|
||||
|
||||
<example>
|
||||
<p>
|
||||
In the following snippet, from an example django app,
|
||||
a name is stored in the database using two different queries.
|
||||
In the following snippet, a user is fetched from the database using three
|
||||
different queries.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In the first case, the query string is built by
|
||||
directly using string formatting from a user-supplied request attribute.
|
||||
directly using string formatting from a user-supplied request parameter.
|
||||
The parameter may include quote characters, so this
|
||||
code is vulnerable to a SQL injection attack.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In the second case, the user-supplied request attribute is passed
|
||||
to the database using query parameters.
|
||||
to the database using query parameters. The database connector library will
|
||||
take care of escaping and inserting quotes as needed.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In the third case, the placeholder in the SQL string has been manually quoted. Since most
|
||||
databaseconnector libraries will insert their own quotes, doing so yourself will make the code
|
||||
vulnerable to SQL injection attacks. In this example, if <code>username</code> was
|
||||
<code>; DROP ALL TABLES -- </code>, the final SQL query would be
|
||||
<code>SELECT * FROM users WHERE username = ''; DROP ALL TABLES -- ''</code>
|
||||
</p>
|
||||
|
||||
<sample src="examples/sql_injection.py" />
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
|
||||
from django.conf.urls import patterns, url
|
||||
from django.conf.urls import url
|
||||
from django.db import connection
|
||||
|
||||
|
||||
def save_name(request):
|
||||
def show_user(request, username):
|
||||
with connection.cursor() as cursor:
|
||||
# BAD -- Using string formatting
|
||||
cursor.execute("SELECT * FROM users WHERE username = '%s'" % username)
|
||||
user = cursor.fetchone()
|
||||
|
||||
if request.method == 'POST':
|
||||
name = request.POST.get('name')
|
||||
curs = connection.cursor()
|
||||
#BAD -- Using string formatting
|
||||
curs.execute(
|
||||
"insert into names_file ('name') values ('%s')" % name)
|
||||
#GOOD -- Using parameters
|
||||
curs.execute(
|
||||
"insert into names_file ('name') values ('%s')", name)
|
||||
# GOOD -- Using parameters
|
||||
cursor.execute("SELECT * FROM users WHERE username = %s", username)
|
||||
user = cursor.fetchone()
|
||||
|
||||
# BAD -- Manually quoting placeholder (%s)
|
||||
cursor.execute("SELECT * FROM users WHERE username = '%s'", username)
|
||||
user = cursor.fetchone()
|
||||
|
||||
urlpatterns = patterns(url(r'^save_name/$',
|
||||
upload, name='save_name'))
|
||||
|
||||
urlpatterns = [url(r'^users/(?P<username>[^/]+)$', show_user)]
|
||||
|
||||
Reference in New Issue
Block a user