永遠用 go-mssqldb 加密

驅動 go-mssqldb 程式支援 Always Encrypted ,用於用戶端加密與解密敏感資料。 啟用後,驅動程式會自動解密加密欄位的資料,並加密傳送到加密欄位的參數值。

啟用「始終加密」

將連線參數設 columnencryptiontrue

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

在 SQL Server 中設定 CMK 時,將金鑰路徑設定為 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"
)

Note

匯入 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 金鑰路徑是 Azure Key Vault 金鑰識別碼 URL:

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

Azure Key Vault 提供者用於azidentity.DefaultAzureCredential認證。 透過環境變數、管理身份、Azure CLI 或其他 Azure 身份函式庫支援的方法來設定憑證。 欲了解更多資訊,請參閱 Microsoft Entra ID 認證

查詢加密欄位

啟用 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.NVarCharMaxmssql.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")))

關於一般參數型別的指引,請參見 資料型別映射

Limitations

  • Always Encrypted 不支援批量複製操作。
  • azuresql 驅動程式和 Always Encrypted 可搭配使用,但您必須同時匯入 azuread 和金鑰提供者套件。
  • charvarchar 的加密插入與更新目前受到限制。 對於必須使用 Always Encrypted 的文字資料,建議使用加密 ncharnvarchar 欄位。
  • 不支援安全飛地。