FlawOpen

flawopen.com/SQL Injection di Python/Django ORM

Apakah Django ORM aman dari SQL Injection secara default?

Halaman referensi
Jawaban singkat

API QuerySet Django memisahkan SQL dari nilai dan mengirim nilai sebagai parameter melalui driver database untuk kueri umum seperti .filter(), .get(), dan .exclude(). Perlindungan ini tidak mencakup semua cara menyusun kueri: raw SQL, ekspresi khusus, serta struktur kueri pilihan pengguna memerlukan pemeriksaan tersendiri.

Menggunakan nilai dengan aman di Django QuerySet

TIDAK AMAN — interpolasi input ke SQL mentah
username = request.GET.get("u", "")
User.objects.raw(
    f"SELECT * FROM myapp_user WHERE username = '{username}'"
)
AMAN — ikat input melalui params raw()
username = request.GET.get("u", "")
User.objects.raw(
    "SELECT * FROM myapp_user WHERE username = %s",
    [username],
)

Batas yang perlu diperhatikan

Model.objects.raw()

Manager.raw() menjalankan SQL yang diberikan. Kirim nilai yang dikendalikan pengguna melalui params dan biarkan placeholder tanpa tanda kutip, misalnya User.objects.raw("SELECT * FROM users WHERE username = %s", [username]). Jangan memasukkan nilai ke SQL dengan f-string, format %, atau konkatenasi. Parameter mewakili nilai, bukan identifier SQL seperti nama tabel atau kolom.

Akses langsung melalui connection.cursor()

Untuk akses database langsung, gunakan cursor.execute(sql, params) dan kirim nilai secara terpisah sesuai placeholder Django. Jangan menginterpolasi nilai ke sql. Tinjau juga ekspresi RawSQL dan Func: konteks template dan argumen bernama dapat diinterpolasi ke SQL, bukan diikat sebagai parameter.

Jalur field yang dikendalikan pengguna

Jalur field dari pengguna pada .filter(**{field: value}) tidak otomatis menjadi SQL Injection: Django memproses nama lookup sebagai struktur kueri. Namun, hal ini dapat membuka field, relasi, atau lookup yang seharusnya tidak tersedia di endpoint, serta menimbulkan error. Petakan opsi urutan dan filter eksternal ke allow-list kecil berisi field model dan lookup yang diizinkan.

Cara mengaudit kueri Django

rg -n '(\.raw\(|RawSQL\(|\.extra\(|connection\.cursor\()' --glob '*.py' .
Cari penggunaan .raw(), RawSQL, .extra(), dan connection.cursor(). Tinjau tiap temuan dan telusuri aliran nilainya: parameter terikat, fragmen SQL tak tepercaya, identifier atau lookup dinamis, serta template Func khusus.

Pertanyaan umum

Apakah extra() aman?

QuerySet.extra() adalah API lama untuk menambahkan fragmen SQL. Hindari di kode baru dan tinjau argumen where serta select yang sudah ada. Utamakan ekspresi QuerySet; jika raw SQL diperlukan, ikat nilai melalui argumen params yang terdokumentasi.

Apakah hal ini juga berlaku untuk Django REST Framework?

Django REST Framework tidak mengubah parameterisasi SQL ORM. Aturan yang sama berlaku untuk kueri dari view, serializer, dan viewset; batasi juga field pengurutan atau filter yang dikendalikan klien dengan allow-list.

Referensi

Lihat juga SQL Injection (CWE-89): cara kerja dan cara mencegahnya di setiap bahasa — flawopen.com Injeksi SQL Doctrine ORM: kueri aman EF Core FromSqlRaw: SQL berparameter yang aman Injeksi SQL FastAPI: Yang Dicegah dan Tidak Dicegah Pydantic GORM Raw SQL: Cegah Injeksi SQL di Go Apakah Escape Tanda Kutip Cukup untuk Mencegah SQL Injection? Apakah memakai ORM cukup untuk mencegah SQL Injection?