mssql-django 中的 Always Encrypted

本文介绍如何通过mssql-django后端将 SQL Server Always Encrypted 与 Django 应用程序配合使用。 Always Encrypted 提供列级加密,用于保护静态和传输中的敏感数据。

先决条件

  • 适用于 SQL Server 的 Microsoft ODBC Driver 17 或 18
  • SQL Server 2016 或更高版本,或Azure SQL 数据库
  • 在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 密钥保管库 中时,请在 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> 替换为应用注册的 应用程序(客户端)ID 和客户端密码值。

Important

不要在 settings.py 中硬编码密钥。 使用环境变量或机密管理器在运行时提供凭据。

带有托管标识的 Azure 密钥保管库

在Azure(例如,Azure 虚拟机或Azure 应用服务)上运行时,请使用托管标识访问Azure 密钥保管库。

系统分配的托管标识

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. 使用 Always Encrypted Azure 密钥保管库 文档中列出的权限,向托管标识授予对存储列主密钥的 Azure 密钥保管库的访问权限。

让 Django 管理加密表

将 Always Encrypted 与 Django 配合使用时,请先在 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管理任务。

不支持的身份验证方法

Always Encrypted 密钥存储访问不支持用户名/密码和Azure 密钥保管库交互式身份验证。