Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Artikel ini membahas praktik keamanan untuk aplikasi Django yang terhubung ke SQL Server melalui mssql-django backend. Praktik ini melengkapi fitur keamanan bawaan Django dan model keamanan SQL Server.
Gunakan autentikasi Microsoft Entra alih-alih kata sandi
Autentikasi Microsoft Entra menghapus kata sandi database tersimpan. Gunakan untuk semua koneksi Azure SQL.
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"HOST": "<your-server>.database.windows.net",
"PORT": "1433",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
"extra_params": "Authentication=ActiveDirectoryMsi",
},
},
}
Untuk daftar lengkap metode autentikasi, catatan penting saat ini, serta TOKEN contoh penggunaan DefaultAzureCredential dan ManagedIdentityCredential, lihat Autentikasi Microsoft Entra dengan mssql-django.
Mengelola kredensial dengan aman
Saat Anda memerlukan autentikasi SQL, jauhkan kredensial dari kode sumber.
Variabel lingkungan
import os
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": os.environ["DB_NAME"],
"USER": os.environ["DB_USER"],
"PASSWORD": os.environ["DB_PASSWORD"],
"HOST": os.environ["DB_HOST"],
"PORT": os.environ.get("DB_PORT", "1433"),
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
},
},
}
Azure Key Vault
Untuk penyebaran produksi, ambil rahasia dari Azure Key Vault:
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
credential = DefaultAzureCredential()
client = SecretClient(vault_url="https://<your-vault>.vault.azure.net/", credential=credential)
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": client.get_secret("db-name").value,
"USER": client.get_secret("db-user").value,
"PASSWORD": client.get_secret("db-password").value,
"HOST": client.get_secret("db-host").value,
"PORT": "1433",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
},
},
}
Perhatian
Jangan pernah menerapkan kredensial ke kontrol sumber. Tambahkan .env file ke .gitignore. Gunakan git-secrets atau hook pre-commit untuk memindai komit kredensial yang tidak disengaja.
Menerapkan enkripsi TLS
SQL Server koneksi harus selalu dienkripsi. Driver ODBC mengenkripsi koneksi secara default dimulai dengan Driver ODBC 18:
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"HOST": "<your-server>.database.windows.net",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
# Encryption is on by default with Driver 18
},
},
}
Jika Anda menggunakan Driver ODBC 17, aktifkan enkripsi secara eksplisit:
"extra_params": "Encrypt=yes"
Perhatian
Gunakan TrustServerCertificate=yes hanya untuk pengembangan lokal dengan sertifikat yang ditandatangani sendiri. Jangan gunakan dalam produksi. Ini menonaktifkan validasi rantai sertifikat dan meningkatkan risiko serangan perantara. Instal sertifikat tepercaya di server dan sambungkan dengan TrustServerCertificate=no.
Menerapkan prinsip hak istimewa terendah
Buat login SQL Server khusus hanya dengan izin yang dibutuhkan aplikasi Anda:
-- Create a login and user for the application
CREATE LOGIN [django_app]
WITH PASSWORD = '<strong-password>';
USE [<your-database>];
CREATE USER [django_app] FOR LOGIN [django_app];
-- Grant minimum required permissions
-- Read and write data
ALTER ROLE db_datareader ADD MEMBER [django_app];
ALTER ROLE db_datawriter ADD MEMBER [django_app];
-- Allow Django to create and alter tables during migrations
GRANT ALTER ON SCHEMA::dbo TO [django_app];
GRANT CREATE TABLE TO [django_app];
GRANT REFERENCES ON SCHEMA::dbo TO [django_app];
Untuk aplikasi yang tidak menjalankan migrasi di lingkungan produksi, hilangkan izin ALTER dan CREATE TABLE:
-- Production application user (read/write only)
ALTER ROLE db_datareader ADD MEMBER [django_app];
ALTER ROLE db_datawriter ADD MEMBER [django_app];
GRANT EXECUTE ON SCHEMA::dbo TO [django_app]; -- If using stored procedures
Jalankan migrasi dari tahap deployment yang terpisah dengan hak akses lebih tinggi:
-- Migration user (used only during deployments)
ALTER ROLE db_ddladmin ADD MEMBER [django_migrations];
Pilih peran yang tepat
Peran database tetap SQL Server diurutkan dari yang hak aksesnya paling rendah hingga yang paling tinggi. Pilih peran dengan hak istimewa paling minimal yang sesuai dengan beban kerja Anda, dan tingkatkan hak akses hanya bila diperlukan:
| Peranan | Grants | Kapan digunakan |
|---|---|---|
| db_datareader |
SELECT pada semua tabel dan tampilan milik pengguna |
Pengguna laporan hanya baca |
| db_datawriter |
INSERT, UPDATE, DELETE pada semua tabel pengguna |
Pengguna aplikasi runtime (gabungkan dengan db_datareader) |
| db_ddladmin | Membuat, mengubah, dan menghilangkan objek skema | Khusus pengguna migrasi atau penerapan |
| db_owner | Semua izin database, termasuk keamanan | Hindari untuk aplikasi; khusus untuk DBA |
Untuk kontrol yang lebih terperinci daripada yang dimungkinkan oleh peran tetap, buat peran database kustom dan GRANT hanya hak akses tertentu pada skema tertentu yang digunakan oleh aplikasi Anda. Menyimpan semua objek aplikasi dalam skema khusus (misalnya, app) memungkinkan Anda membatasi grant dengan GRANT ... ON SCHEMA::app alih-alih mengandalkan peran db_datareader dan db_datawriter tingkat database.
Note
Jangan gunakan akun sa atau peran database tetap db_owner untuk koneksi aplikasi. Jika aplikasi disusupi, penyerang mendapatkan kontrol database penuh.
Mencegah injeksi SQL
ORM Django secara otomatis memparametrisasi semua kueri. Injeksi SQL hanya berisiko ketika Anda menggunakan SQL mentah:
Aman: Kueri ORM
# Django parameterizes these automatically
users = User.objects.filter(email=user_input)
products = Product.objects.filter(price__lte=max_price)
Aman: SQL mentah yang diparameterkan
from django.db import connection
with connection.cursor() as cursor:
cursor.execute(
"SELECT * FROM products WHERE category = %s AND price < %s",
[category, max_price],
)
Tidak aman: Pemformatan string dalam SQL mentah
# NEVER do this - vulnerable to SQL injection
cursor.execute(f"SELECT * FROM products WHERE category = '{category}'")
cursor.execute("SELECT * FROM products WHERE category = '%s'" % category)
Ekstra dan RawSQL
Django dan extra()RawSQL() menerima fragmen SQL mentah. Selalu gunakan parameter:
# Safe - parameterized
Product.objects.extra(where=["category = %s"], params=[category])
from django.db.models.expressions import RawSQL
Product.objects.annotate(
discount=RawSQL("price * %s", [discount_rate])
)
Important
Jangan pernah menggunakan extra() atau RawSQL() dengan pemformatan string. Ini melewati parameterisasi otomatis ORM.
Mengonfigurasi middleware keamanan Django
Aktifkan middleware keamanan bawaan Django untuk melindungi lapisan web. Meskipun ini tidak khusus untuk basis data, ini melindungi aplikasi yang terhubung ke basis data Anda:
# settings.py
# HTTPS enforcement
SECURE_SSL_REDIRECT = True
SECURE_HSTS_SECONDS = 31536000 # 1 year
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
# Cookie security
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
# Content security
SECURE_CONTENT_TYPE_NOSNIFF = True
Mengaudit akses database
Aktifkan audit SQL Server untuk melacak operasi database dari aplikasi Django Anda:
-- Create a server audit (Azure SQL uses Azure SQL Auditing instead)
CREATE SERVER AUDIT [DjangoAudit]
TO FILE (FILEPATH = 'C:\Audits\')
WITH (ON_FAILURE = CONTINUE);
ALTER SERVER AUDIT [DjangoAudit] WITH (STATE = ON);
-- Create a database audit specification
USE [<your-database>];
CREATE DATABASE AUDIT SPECIFICATION [DjangoDbAudit]
FOR SERVER AUDIT [DjangoAudit]
ADD (SELECT, INSERT, UPDATE, DELETE ON SCHEMA::dbo BY [django_app])
WITH (STATE = ON);
Untuk Azure SQL Database, aktifkan audit melalui portal Azure atau Azure CLI:
az sql db audit-policy update --resource-group <rg> --server <server> \
--name <database> --state Enabled \
--storage-account <storage-account>
Mengamankan kolom sensitif dengan Always Encrypted
Untuk enkripsi tingkat kolom data sensitif seperti SSN, nomor kartu kredit, atau data gaji, gunakan Always Encrypted. Driver ODBC menangani enkripsi dan dekripsi secara transparan:
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
"extra_params": "ColumnEncryption=Enabled",
},
},
}
Untuk penyiapan terperinci termasuk manajemen kunci dengan Azure Key Vault, lihat Always Encrypted dengan mssql-django.
Daftar periksa keamanan
| Kategori | Praktik | Prioritas |
|---|---|---|
| Authentication | Gunakan autentikasi Microsoft Entra untuk Azure SQL. | High |
| Credentials | Simpan rahasia dalam variabel lingkungan atau Azure Key Vault. | High |
| Encryption | Gunakan Driver ODBC 18 (enkripsi aktif secara default) atau Encrypt=yes. |
High |
| Injeksi | Gunakan kueri ORM atau SQL mentah berparameter. Jangan pernah memformat SQL sebagai string. | High |
| Hak istimewa terkecil | Buat login khusus dengan izin minimum yang diperlukan. | High |
| TLS | Jangan gunakan TrustServerCertificate=yes dalam produksi. |
High |
| Django | Aktifkan SECURE_SSL_REDIRECT, amankan cookie, HSTS. |
Medium |
| Auditing | Aktifkan audit SQL Server atau Audit Azure SQL. | Medium |
| Enkripsi kolom | Gunakan Always Encrypted untuk kolom yang sangat sensitif. | Low |
| Koneksi | Atur CONN_MAX_AGE dan CONN_HEALTH_CHECKS untuk mencegah koneksi kedaluarsa. |
Low |