永遠用 mssql-django 加密

本文說明如何透過 mssql-django 後端,在 Django 應用程式中使用 SQL Server Always Encrypted。 Always Encrypted 提供欄位層級加密,保護靜態及傳輸中的敏感資料。

先決條件

  • 適用於 SQL Server 的 Microsoft ODBC Driver 17 或 18
  • SQL Server 2016 或更新版本,或者 Azure SQL Database
  • SQL Server端設定的欄位加密(欄位主金鑰與欄位加密金鑰)

運作原理

Always Encrypted 是由 ODBC 驅動層處理,而非 Django 本身。 啟用 ColumnEncryption ODBC 參數時,驅動程式會在資料在應用程式與 SQL Server 之間傳遞時自動加密與解密。 無論欄位是否加密,Django 模型和查詢的運作方式相同。

Windows 的憑證存放區

當資料行主金鑰儲存在 Windows 憑證存放區時,將 ColumnEncryption=Enabled 新增至 extra_params 以啟用 Always Encrypted:

DATABASES = {
    "default": {
        "ENGINE": "mssql",
        "NAME": "<your-database>",
        "USER": "<your-username>",
        "PASSWORD": "<your-password>",
        "HOST": "<your-server>",
        "PORT": "1433",
        "OPTIONS": {
            "driver": "ODBC Driver 18 for SQL Server",
            "extra_params": "ColumnEncryption=Enabled",
        },
    },
}

這種方法只適用於 Windows。

使用用戶端 ID 和密碼的 Azure 金鑰保存庫

當欄位主金鑰儲存在 Azure Key Vault 時,請在以下欄位提供應用程式憑證:extra_params

DATABASES = {
    "default": {
        "ENGINE": "mssql",
        "NAME": "<your-database>",
        "USER": "<your-username>",
        "PASSWORD": "<your-password>",
        "HOST": "<your-server>",
        "PORT": "1433",
        "OPTIONS": {
            "driver": "ODBC Driver 18 for SQL Server",
            "extra_params": (
                "ColumnEncryption=Enabled;"
                "KeyStoreAuthentication=KeyVaultClientSecret;"
                "KeyStorePrincipalId=<application-client-id>;"
                "KeyStoreSecret=<client-secret>"
            ),
        },
    },
}

<application-client-id><client-secret> 替換為應用程式註冊的 應用程式(用戶端)識別碼 和用戶端密碼值。

Important

不要在 settings.py 中硬編碼機密資訊。 使用環境變數或秘密管理器在執行時提供憑證。

具有受控識別的 Azure Key Vault

在 Azure 上執行時(例如 Azure 虛擬機器 或 Azure App 服務),請使用管理身份來存取 Azure Key Vault。

系統指派的管理身份識別

除了以下 KeyStoreAuthentication 參數外,不需要額外的配置:

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": (
                "ColumnEncryption=Enabled;"
                "KeyStoreAuthentication=KeyVaultManagedIdentity"
            ),
        },
    },
}

使用者指派的受控識別

加入受控識別的用戶端 ID(也稱為應用程式 ID):

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": (
                "ColumnEncryption=Enabled;"
                "KeyStoreAuthentication=KeyVaultManagedIdentity;"
                "KeyStorePrincipalId=<managed-identity-client-id>"
            ),
        },
    },
}

授與受控識別權限

  1. 授與受控識別存取您 Azure SQL 資料庫的權限:

    CREATE USER [<identity-name>] FOR EXTERNAL PROVIDER;
    
    ALTER ROLE db_datareader ADD MEMBER [<identity-name>];
    ALTER ROLE db_datawriter ADD MEMBER [<identity-name>];
    
    GRANT VIEW ANY COLUMN MASTER KEY DEFINITION TO [<identity-name>];
    GRANT VIEW ANY COLUMN ENCRYPTION KEY DEFINITION TO [<identity-name>];
    
  2. 授權管理身份存取存放欄位主金鑰的 Azure Key Vault,權限列於 Always Encrypted Azure Key Vault 文件中。

讓 Django 管理加密資料表

使用 Django 的 Always Encrypted 時,請先在 SQL Server 上設定加密物件,然後再執行遷移。

建議順序:

  1. 在 SQL Server 或 Azure SQL 上建立欄位主金鑰(CMK)和欄位加密金鑰(CEK)。
  2. 在 Django 連線設定中設定 ColumnEncryption=Enabled
  3. 執行 Django 遷移。
  4. 使用 SQL Server Management Studio 或 T-SQL 加密目標欄位。

執行遷移:

python manage.py migrate

mssql-django 不會建立或管理 Always Encrypted 金鑰的元資料。 金鑰建立與欄位加密政策仍屬於 SQL Server 管理任務。

不支援的認證方法

使用者名稱/密碼和 Azure Key Vault 互動式認證不支援 Always Encrypted 金鑰儲存存取。