flawopen.com/SQL Injection em Python/Django ORM
O ORM do Django é seguro contra SQL Injection?
A API QuerySet do Django separa o SQL dos valores e envia parâmetros ao driver do banco nas consultas comuns, como .filter(), .get() e .exclude(). Isso não protege todas as formas de montar consultas: SQL bruto, expressões personalizadas e estrutura da consulta definida pelo usuário exigem revisão própria.
Uso seguro de valores em QuerySets do Django
username = request.GET.get("u", "")
User.objects.raw(
f"SELECT * FROM myapp_user WHERE username = '{username}'"
)
username = request.GET.get("u", "")
User.objects.raw(
"SELECT * FROM myapp_user WHERE username = %s",
[username],
)
Onde a proteção exige atenção
Manager.raw() executa o SQL fornecido. Passe valores controlados pelo usuário por params e deixe os placeholders sem aspas, por exemplo User.objects.raw("SELECT * FROM users WHERE username = %s", [username]). Não insira valores no SQL com f-strings, formatação % ou concatenação. Parâmetros representam valores, não identificadores SQL, como nomes de tabelas ou colunas.
No acesso direto ao banco, use cursor.execute(sql, params) e passe os valores separadamente conforme os placeholders documentados pelo Django. Não interpole valores em sql. Revise também RawSQL e expressões Func: contexto de template e argumentos nomeados podem ser interpolados no SQL, em vez de vinculados como parâmetros.
Um caminho de campo controlado pelo usuário em .filter(**{field: value}) não é automaticamente SQL Injection: o Django interpreta nomes de lookup como estrutura da consulta. Ainda assim, pode expor campos, relações ou lookups que o endpoint não deveria oferecer, além de causar erros. Mapeie opções externas de ordenação e filtro para uma allow-list restrita de campos e lookups permitidos.
Como auditar consultas Django
rg -n '(\.raw\(|RawSQL\(|\.extra\(|connection\.cursor\()' --glob '*.py' ..raw(), RawSQL, .extra() e connection.cursor(). Revise cada ocorrência e rastreie os valores até a consulta; verifique parâmetros vinculados, fragmentos SQL não confiáveis, identificadores e lookups dinâmicos, além de templates customizados Func.Perguntas frequentes
QuerySet.extra() é uma API legada para adicionar fragmentos SQL. Evite-a em código novo e revise com cuidado os argumentos where e select existentes. Prefira expressões do QuerySet; quando SQL bruto for necessário, vincule valores pelo argumento documentado params.
O Django REST Framework não altera a parametrização SQL do ORM. As mesmas regras se aplicam a consultas de views, serializers e viewsets; também use allow-lists para campos de ordenação ou filtro controlados pelo cliente.
Referências
- Django docs — SQL injection protection
- flawopen.com — SQL Injection in Python
- Django docs — Performing raw SQL queries
- Django docs — Query expressions and RawSQL