Osvědčené postupy zabezpečení pro mssql-django

Tento článek popisuje postupy zabezpečení pro aplikace Django, které se připojují k SQL Server prostřednictvím back-endumssql-django. Tyto postupy doplňují integrované funkce zabezpečení Django a model zabezpečení SQL Server.

Použití ověřování Microsoft Entra místo hesel

Ověřování Microsoft Entra odstraňuje potřebu ukládat hesla k databázi. Použijte ho pro všechna připojení 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",
        },
    },
}

Úplný seznam metod ověřování, aktuálních upozornění a TOKEN příkladů pro DefaultAzureCredential a ManagedIdentityCredential najdete v článku ověřování Microsoft Entra pomocí mssql-django.

Zabezpečená správa přihlašovacích údajů

Pokud potřebujete ověřování SQL, zachovejte přihlašovací údaje mimo zdrojový kód.

Proměnné prostředí

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

Pro produkční nasazení načtěte tajné kódy z 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",
        },
    },
}

Caution

Nikdy nesvěřujte přihlašovací údaje do správy zdrojového kódu. Přidat soubory .env do .gitignore. Použijte git-secrets nebo pre-commit hooky ke kontrole commitů, které omylem obsahují přihlašovací údaje.

Vynucení šifrování TLS

SQL Server připojení by měla být vždy šifrovaná. Ovladač ODBC ve výchozím nastavení šifruje připojení počínaje verzí ODBC Driver 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
        },
    },
}

Pokud používáte ovladač ODBC 17, povolte šifrování explicitně:

"extra_params": "Encrypt=yes"

Caution

Používejte TrustServerCertificate=yes pouze pro místní vývoj s certifikáty podepsanými svým držitelem. Nepoužívejte ho v produkčním prostředí. Zakáže ověřování řetězce certifikátů a zvyšuje riziko útoku typu man-in-the-middle. Nainstalujte na server důvěryhodný certifikát a připojte se pomocí TrustServerCertificate=no.

Použití principu nejnižšího oprávnění

Vytvořte vyhrazená SQL Server přihlášení pouze s oprávněními, která vaše aplikace potřebuje:

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

U aplikací, u kterých se v produkčním prostředí nespouštějí migrace, vynechte oprávnění ALTER a 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

Spusťte migrace v rámci samostatného kroku nasazení s vyššími oprávněními:

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

Volba správné role

SQL Server pevné databázové role jsou seřazené od nejméně po nejvíce privilegované. Vyberte nejméně privilegovanou roli, která pokrývá vaši úlohu, a v případě potřeby pouze eskalujte:

Úloha Grants Kdy ho použít
db_datareader SELECT ve všech uživatelských tabulkách a zobrazeních Uživatelé pro vykazování s oprávněním jen pro čtení
db_datawriter INSERT, UPDATE, DELETE ve všech uživatelských tabulkách Uživatel aplikace runtime (kombinování s db_datareader)
db_ddladmin Vytváření, změny a odstraňování objektů schématu Pouze pro uživatele migrace nebo nasazení
db_owner Všechna oprávnění k databázi, včetně zabezpečení Nepoužívejte pro aplikace; vyhraďte pro správce databází

Pro jemně odstupňované řízení, než umožňují pevné role, vytvořte vlastní roli databáze a GRANT pouze konkrétní oprávnění ke konkrétnímu schématu, které vaše aplikace používá. Uložení všech objektů aplikace do vyhrazeného schématu (například app) umožňuje omezit rozsah oprávnění pomocí GRANT ... ON SCHEMA::app namísto spoléhání na celo-databázové role db_datareader a db_datawriter.

Note

Nepoužívejte sa účet ani db_owner pevnou roli databáze pro připojení aplikací. Pokud dojde k ohrožení zabezpečení aplikace, útočník získá úplnou kontrolu nad databází.

Prevence injektáže SQL

Django ORM parametrizuje všechny dotazy automaticky. Injektáž SQL představuje riziko pouze v případech, kdy používáte nezpracovaný SQL:

Bezpečné: Dotazy ORM

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

Bezpečné: Parametrizované nezpracované 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],
    )

Nebezpečné: Formátování řetězců v nezpracovaných 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 a RawSQL

Django přijímá extra()RawSQL() nezpracované fragmenty SQL. Vždy používat parametry:

# 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

Nikdy nepoužívejte extra() ani RawSQL() s formátováním řetězců. Tyto obcházejí automatickou parametrizaci ORM.

Konfigurace middlewaru zabezpečení Django

Povolte vestavěný bezpečnostní middleware frameworku Django pro ochranu webové vrstvy. I když nejsou specifické pro databázi, chrání aplikaci, která se připojuje k vaší databázi:

# 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

Auditovat přístup k databázi

Povolte auditování SQL Server ke sledování databázových operací z aplikace Django:

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

U Azure SQL Database povolte auditování prostřednictvím portálu Azure nebo Azure CLI:

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

Zabezpečení citlivých sloupců pomocí funkce Always Encrypted

Pro šifrování citlivých dat na úrovni sloupců, jako jsou rodná čísla, čísla platebních karet nebo mzdové údaje, použijte funkci Always Encrypted. Ovladač ODBC zpracovává šifrování a dešifrování transparentně:

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

Podrobné nastavení včetně správy klíčů s Azure Key Vault najdete v tématu Always Encrypted s mssql-django.

Kontrolní seznam zabezpečení

Kategorie Practice Priorita
Ověřování Pro Azure SQL použijte ověřování Microsoft Entra. Vysoko
Credentials Ukládejte tajné kódy do proměnných prostředí nebo Azure Key Vault. Vysoko
Encryption Použijte ODBC Driver 18 (šifrování je ve výchozím nastavení zapnuté) nebo Encrypt=yes. Vysoko
Injekce Použijte dotazy ORM nebo parametrizované nezpracované SQL. Nikdy neformátujte SQL jako řetězec. Vysoko
Nejnižší oprávnění Vytvořte vyhrazená přihlášení s minimálními požadovanými oprávněními. Vysoko
protokol TLS Nepoužívejte TrustServerCertificate=yes v produkčním prostředí. Vysoko
Django Povolte SECURE_SSL_REDIRECT, zabezpečené soubory cookie, HSTS. Středně
Auditing Povolte auditování SQL Server nebo auditování Azure SQL. Středně
Šifrování sloupců Používejte funkci Always Encrypted pro vysoce citlivé sloupce. Nízká úroveň
Připojení Nastavte CONN_MAX_AGE a CONN_HEALTH_CHECKS, abyste zabránili neaktivním připojením. Nízká úroveň