Всегда шифруется с помощью go-mssqldb

go-mssqldb Драйвер поддерживает Always Encrypted для клиентского шифрования и дешифрования конфиденциальных данных. При включении драйвер автоматически расшифровывает данные из зашифрованных столбцов и шифрует значения параметров, отправляемые в зашифрованные столбцы.

Включить Always Encrypted

Установить columnencryption параметр соединения на true:

sqlserver://<user>:<password>@<server>?database=AdventureWorks2025&columnencryption=true

Также необходимо импортировать как минимум один пакет поставщика главного ключа столбца (CMK). Без провайдера драйвер не может получить доступ к ключам шифрования.

Поставщики главных ключей столбцов

Драйвер поддерживает трех поставщиков хранилищ ключей. Импортируйте пакет провайдера как побочный импорт для регистрации.

Локальный сертификат (PFX)

localcert Провайдер считывает приватные ключи из файлов PFX (PKCS #12) в локальной файловой системе. Имя провайдера в метаданных CMK — pfx.

import (
    _ "github.com/microsoft/go-mssqldb"
    _ "github.com/microsoft/go-mssqldb/aecmk/localcert"
)

При настройке CMK в SQL Server установите путь ключа в расположение PFX-файла:

CREATE COLUMN MASTER KEY MyCMK
WITH (
    KEY_STORE_PROVIDER_NAME = 'pfx',
    KEY_PATH = '/path/to/certificate.pfx'
);

Если PFX-файл защищён паролем, установите пароль как переменную среды или через pfxpassword параметр соединения.

Хранилище сертификатов Windows

MSSQL_CERTIFICATE_STORE Провайдер получает доступ к сертификатам в Хранилище сертификатов Windows. Этот провайдер работает только на Windows.

import (
    _ "github.com/microsoft/go-mssqldb"
    _ "github.com/microsoft/go-mssqldb/aecmk/localcert"
)

Замечание

Импорт localcert также регистрирует поставщика хранилища сертификатов Windows в Windows. Отдельный импорт не требуется.

Формат пути ключа CMK выглядит CurrentUser/My/<thumbprint> или LocalMachine/My/<thumbprint>:

CREATE COLUMN MASTER KEY MyCMK
WITH (
    KEY_STORE_PROVIDER_NAME = 'MSSQL_CERTIFICATE_STORE',
    KEY_PATH = 'CurrentUser/My/<CERTIFICATE_THUMBPRINT>'
);

Azure Key Vault

Поставщик akv извлекает главные ключи столбцов из хранилища ключей Azure Key Vault.

import (
    _ "github.com/microsoft/go-mssqldb"
    _ "github.com/microsoft/go-mssqldb/aecmk/akv"
)

Путь к ключу CMK — это URL-адрес идентификатора ключа Azure Key Vault:

CREATE COLUMN MASTER KEY MyCMK
WITH (
    KEY_STORE_PROVIDER_NAME = 'AZURE_KEY_VAULT',
    KEY_PATH = 'https://<VAULT_NAME>.vault.azure.net/keys/<KEY_NAME>/<KEY_VERSION>'
);

Provider Azure Key Vault использует azidentity.DefaultAzureCredential для аутентификации. Настраивайте учетные данные через переменные среды, управляемую идентичность, Azure CLI или другие методы, поддерживаемые библиотекой Azure Identity. Дополнительные сведения см. в разделе проверки подлинности Идентификатора Microsoft Entra.

Запрос зашифрованных столбцов

С включённым Always Encrypted и зарегистрированным провайдером запросы работают прозрачно:

import (
    "context"
    "database/sql"
    "fmt"
    "log"

    _ "github.com/microsoft/go-mssqldb"
    _ "github.com/microsoft/go-mssqldb/aecmk/localcert"
)

func main() {
    db, err := sql.Open("sqlserver",
        "sqlserver://<user>:<password>@<server>?database=AdventureWorks2025&columnencryption=true")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    ctx := context.Background()

    // Reads automatically decrypt encrypted columns
    var ssn string
    err = db.QueryRowContext(ctx,
        "SELECT SSN FROM Patients WHERE Id = @p1",
        sql.Named("p1", 1)).Scan(&ssn)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("SSN:", ssn)

    // Parameters are automatically encrypted for encrypted columns
    _, err = db.ExecContext(ctx,
        "INSERT INTO Patients (Name, SSN) VALUES (@p1, @p2)",
        sql.Named("p1", "Alice"),
        sql.Named("p2", "123-45-6789"))
    if err != nil {
        log.Fatal(err)
    }
}

Точно сопоставьте типы параметров

Шифрование параметров в Always Encrypted предъявляет более строгие требования, чем обычная привязка параметров. Драйвер запрашивает у SQL Server метаданные шифрования перед отправкой значений, поэтому тип параметра Go должен точно совпадать с типом столбца SQL Server.

  • Параметр Go string отправляется nvarchar по умолчанию.
  • Используйте специфичные для драйвера типы, такие как mssql.NVarCharMax, mssql.DateTime1 или mssql.DateTimeOffset, когда для зашифрованного столбца используется более специфический тип SQL Server.
  • Если тип параметра не совпадает с типом зашифрованного столбца, запрос может провалиться при обнаружении метаданных по параметрам с ошибкой несоответствия типа.

Например, если зашифрованный столбец — nvarchar(max), лучше использовать mssql.NVarCharMax, когда требуется точное совпадение длинной строки:

_, err := db.ExecContext(ctx,
    "INSERT INTO Patients (Notes) VALUES (@p1)",
    sql.Named("p1", mssql.NVarCharMax("Sensitive note text")))

Для общих рекомендаций по типам параметров см. Отображения типов данных.

Ограничения

  • Always Encrypted не работает с операциями массового копирования.
  • azuresql драйвер и Always Encrypted можно использовать вместе, но необходимо импортировать пакеты azuread и поставщика ключей.
  • В настоящее время количество шифрованных char , varchar вставок и обновлений ограничено. Предпочитайте зашифрованные nchar или nvarchar столбцы для текстовых данных, которые обязательно используют Always Encrypted.
  • Безопасные анклавы не поддерживаются.