flawopen.com/SQL Injection in Python/Django ORM
Schützt das Django-ORM standardmäßig vor SQL Injection?
Die QuerySet-API von Django trennt bei üblichen Abfragen wie .filter(), .get() und .exclude() den SQL-Code von den Werten und übergibt Werte als Parameter an den Datenbanktreiber. Dieser Schutz deckt nicht jede Art des Abfrageaufbaus ab: Raw SQL, benutzerdefinierte Ausdrücke und vom Benutzer bestimmte Query-Strukturen brauchen eine eigene Prüfung.
Werte sicher in Django-QuerySets verwenden
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],
)
Wo der Schutz besondere Sorgfalt erfordert
Manager.raw() führt das übergebene SQL aus. Übergib benutzergesteuerte Werte über params und setze Platzhalter nicht in Anführungszeichen, etwa User.objects.raw("SELECT * FROM users WHERE username = %s", [username]). Füge Werte nicht mit f-Strings, %-Formatierung oder Verkettung in SQL ein. Parameter stehen für Werte, nicht für SQL-Bezeichner wie Tabellen- oder Spaltennamen.
Verwende beim direkten Datenbankzugriff cursor.execute(sql, params) und übergib Werte separat mit den dokumentierten Django-Platzhaltern. Interpoliere keine Werte in sql. Prüfe auch RawSQL und Func-Ausdrücke: Template-Kontext und benannte Argumente können in SQL interpoliert statt als Parameter gebunden werden.
Ein benutzergesteuerter Feldpfad in .filter(**{field: value}) ist nicht automatisch SQL Injection: Django löst Lookup-Namen als Query-Struktur auf. Trotzdem kann dies Felder, Beziehungen oder Lookups offenlegen, die der Endpunkt nicht anbieten sollte, und Fehler auslösen. Ordne externe Sortier- und Filteroptionen einer engen Allowlist erlaubter Modellfelder und Lookups zu.
Django-Abfragen prüfen
rg -n '(\.raw\(|RawSQL\(|\.extra\(|connection\.cursor\()' --glob '*.py' ..raw(), RawSQL, .extra() und connection.cursor(). Prüfe jeden Treffer und verfolge Werte bis zur Abfrage: gebundene Parameter, nicht vertrauenswürdige SQL-Fragmente, dynamische Bezeichner oder Lookups sowie benutzerdefinierte Func-Templates.Häufige Fragen
QuerySet.extra() ist eine ältere API zum Ergänzen roher SQL-Fragmente. Verwende sie nicht in neuem Code und prüfe bestehende Argumente für where und select sorgfältig. Bevorzuge QuerySet-Ausdrücke; wenn Raw SQL nötig ist, binde Werte über das dokumentierte Argument params.
Django REST Framework ändert die SQL-Parametrisierung des ORM nicht. Dieselben Regeln gelten für Abfragen aus Views, Serializers und Viewsets. Begrenze außerdem clientgesteuerte Sortier- und Filterfelder mit einer Allowlist.
Quellen
- Django docs — SQL injection protection
- flawopen.com — SQL Injection in Python
- Django docs — Performing raw SQL queries
- Django docs — Query expressions and RawSQL