Aanbevolen beveiligingsprocedures voor mssql-django

In dit artikel worden beveiligingsprocedures beschreven voor Django-toepassingen die verbinding maken met SQL Server via de mssql-django back-end. Deze procedures vormen een aanvulling op de ingebouwde beveiligingsfuncties van Django en het beveiligingsmodel van SQL Server.

Gebruik Microsoft Entra verificatie in plaats van wachtwoorden

Microsoft Entra verificatie elimineert opgeslagen databasewachtwoorden. Gebruik deze voor alle Azure SQL verbindingen.

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",
        },
    },
}

Zie Microsoft Entra-authenticatie met mssql-django voor de volledige lijst met authenticatiemethoden, huidige aandachtspunten en TOKEN voorbeelden met DefaultAzureCredential en ManagedIdentityCredential.

Referenties veilig beheren

Wanneer u SQL-verificatie nodig hebt, moet u referenties buiten de broncode houden.

Omgevingsvariabelen

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

Voor productie-implementaties haalt u geheimen op uit 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",
        },
    },
}

Waarschuwing

Voer nooit referenties door naar broncodebeheer. Voeg .env bestanden toe aan .gitignore. Gebruik git-secrets of pre-commit-hooks om te scannen op commits waarin per ongeluk inloggegevens zijn opgenomen.

TLS-versleuteling afdwingen

SQL Server verbindingen moeten altijd worden versleuteld. Het ODBC-stuurprogramma versleutelt standaard verbindingen vanaf ODBC-stuurprogramma 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
        },
    },
}

Als u ODBC-stuurprogramma 17 gebruikt, schakelt u versleuteling expliciet in:

"extra_params": "Encrypt=yes"

Waarschuwing

Alleen gebruiken TrustServerCertificate=yes voor lokale ontwikkeling met zelfondertekende certificaten. Gebruik het niet in productie. Hierdoor wordt de validatie van de certificaatketen uitgeschakeld en neemt het man-in-the-middle-risico toe. Installeer een vertrouwd certificaat op de server en maak verbinding met TrustServerCertificate=no.

Het principe van minimale bevoegdheden toepassen

Maak toegewezen SQL Server aanmeldingen met alleen de machtigingen die uw toepassing nodig heeft:

-- 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];

Voor toepassingen die geen migraties uitvoeren in productie, laat u de ALTER en CREATE TABLE machtigingen weg:

-- 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

Voer migraties uit vanuit een afzonderlijke, meer bevoegde implementatiestap:

-- Migration user (used only during deployments)
ALTER ROLE db_ddladmin ADD MEMBER [django_migrations];

De juiste rol kiezen

SQL Server vaste databaserollen worden geordend van minst naar meest bevoegd. Kies de rol met minimale bevoegdheden die betrekking heeft op uw workload en escaleer alleen wanneer dat nodig is:

Role Grants Wanneer gebruiken
db_datareader SELECT op alle gebruikerstabellen en views Gebruikers met alleen-leestoegang tot rapportages
db_datawriter INSERT, UPDATE, DELETE op alle gebruikerstabellen Runtime-toepassingsgebruiker (combineren met db_datareader)
db_ddladmin Schemaobjecten maken, wijzigen en verwijderen Alleen migratie- of implementatiegebruiker
db_owner Alle databasemachtigingen, inclusief beveiliging Vermijd voor toepassingen; reserveren voor DBA's

Voor fijnmazigere controle dan met de vaste rollen mogelijk is, maakt u een aangepaste databaserol aan en GRANT alleen de specifieke machtigingen op het specifieke schema dat uw app gebruikt. Door alle toepassingsobjecten in een toegewezen schema onder te brengen (bijvoorbeeld app), kunt u machtigingen afbakenen met GRANT ... ON SCHEMA::app in plaats van te vertrouwen op de databrede rollen db_datareader en db_datawriter.

Note

Gebruik niet het account sa of de vaste databaserol db_owner voor applicatieverbindingen. Als de toepassing is aangetast, krijgt een aanvaller volledige databasebeheer.

SQL-injectie voorkomen

Django's ORM parameteriseert automatisch alle query's. SQL-injectie is alleen een risico wanneer u onbewerkte SQL gebruikt:

Veilig: query’s van ORM

# Django parameterizes these automatically
users = User.objects.filter(email=user_input)
products = Product.objects.filter(price__lte=max_price)

Veilig: Geparameteriseerde onbewerkte SQL

from django.db import connection

with connection.cursor() as cursor:
    cursor.execute(
        "SELECT * FROM products WHERE category = %s AND price < %s",
        [category, max_price],
    )

Onveilig: Tekenreeksopmaak in onbewerkte SQL

# 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)

Extra en RawSQL

Django's extra() en RawSQL() accepteren onbewerkte SQL-fragmenten. Altijd parameters gebruiken:

# 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

Gebruik nooit extra() of RawSQL() met tekenreeksopmaak. Hiermee wordt de automatische parameterisatie van de ORM overgeslagen.

Django-beveiligings-middleware configureren

Schakel de ingebouwde beveiligings-middleware van Django in om de weblaag te beveiligen. Hoewel deze niet databasespecifiek zijn, beveiligen ze de toepassing die verbinding maakt met uw database:

# 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

Databasetoegang controleren

Schakel SQL Server controle in om databasebewerkingen bij te houden vanuit uw Django-toepassing:

-- 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);

Schakel voor Azure SQL Database controle in via de Azure-portal of Azure CLI:

az sql db audit-policy update --resource-group <rg> --server <server> \
    --name <database> --state Enabled \
    --storage-account <storage-account>

Gevoelige kolommen beveiligen met Always Encrypted

Gebruik Always Encrypted voor versleuteling op kolomniveau van gevoelige gegevens, zoals SSN's, creditcardnummers of salarisgegevens. Het ODBC-stuurprogramma verwerkt versleuteling en ontsleuteling transparant:

DATABASES = {
    "default": {
        "ENGINE": "mssql",
        "NAME": "<your-database>",
        "OPTIONS": {
            "driver": "ODBC Driver 18 for SQL Server",
            "extra_params": "ColumnEncryption=Enabled",
        },
    },
}

Zie Always Encrypted met mssql-django voor gedetailleerde instellingen, waaronder sleutelbeheer met Azure Key Vault.

Controlelijst voor beveiliging

Categorie Practice Priority
Authentication Gebruik Microsoft Entra verificatie voor Azure SQL. Hoog
Credentials Geheimen opslaan in omgevingsvariabelen of Azure Key Vault. Hoog
Encryption Gebruik ODBC-stuurprogramma 18 (standaard versleuteling ingeschakeld) of Encrypt=yes. Hoog
Injectie Gebruik ORM-query's of geparameteriseerde onbewerkte SQL. Formatteer SQL nooit met tekenreeksen. Hoog
Minimale bevoegdheid Maak toegewezen aanmeldingen met minimale vereiste machtigingen. Hoog
TLS Gebruik niet TrustServerCertificate=yes in productie. Hoog
Django Schakel SECURE_SSL_REDIRECT, beveiligde cookies en HSTS in. Gemiddeld
Auditing Schakel SQL Server controle of Azure SQL controle in. Gemiddeld
Kolomversleuteling Gebruik Always Encrypted voor zeer gevoelige kolommen. Laag
Verbinding Stel CONN_MAX_AGE en CONN_HEALTH_CHECKS in om verouderde verbindingen te voorkomen. Laag