This check looks for ways that Django SQL Injection protection is being bypassed, by using quoted parameters.
The check looks at the following use cases:
- Use of
RawSQL()
constructor directly - Use of
cursor.execute()
- Use of
raw()
on aManager
instance
Whilst the methods support parametrized queries, if the %s
value is quoted with single-quotes, the value is still vulnerable to SQL injection.
This also applies to parametrized arguments, where it includes a substitute reference, e.g. '%(variable)s'
.
The first example is using the RawSQL constructor directly and annotating a query set:
from django.db.models.expressions import RawSQL
qs.annotate(val=RawSQL("select col from sometable where othercol = '%s'", (someparam,))) # this is bad!
Another example is using the raw()
method on a manager to filter results, exposing SQL injection:
from django import things
from .models import User
def my_view(self):
User.objects.raw("SELECT * FROM myapp_person WHERE last_name = '%s'", [lname]) # this is also bad!
Cursors can also be exploited using the same technique:
from django.db import connection
def my_custom_sql(self):
with connection.cursor() as cursor:
cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz])
cursor.execute("SELECT foo FROM bar WHERE baz = '%s'", [self.baz])
row = cursor.fetchone()
return row
Remove the quotations from the string values:
("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz]) # good
("UPDATE bar SET foo = 1 WHERE baz = '%s'", [self.baz]) # bad!