Verwenden von Always Encrypted mit dem .NET Framework-Datenanbieter für SQL Server

Gilt für:SQL ServerAzure SQL-DatenbankAzure SQL Managed Instance

Dieser Artikel enthält Informationen zum Entwickeln von .NET Framework-Anwendungen mit Always Encrypted oder Always Encrypted mit sicheren Enklaven und dem .NET Framework-Datenanbieter für SQL Server (System.Data.SqlClient).

Hinweis

Die Verwendung des .NET Framework-Datenanbieters für SQL Server (System.Data.SqlClient) wird für die neue Entwicklung nicht empfohlen. Weitere Informationen finden Sie unter System.Data.SqlClient.

Always Encrypted ermöglicht Clientanwendungen das Verschlüsseln von vertraulichen Daten in einer Weise, dass weder die Daten noch die Verschlüsselungsschlüssel zu irgendeinem Zeitpunkt gegenüber SQL Server oder Azure SQL-Datenbank offengelegt werden. Ein Treiber, bei dem „Always Encrypted“ aktiviert ist, z. B. der .NET Framework-Datenanbieter für SQL Server, erreicht dies durch die transparente Ver- und Entschlüsselung von sensiblen Daten in der Clientanwendung. Der Treiber ermittelt automatisch, welche Abfrageparameter vertraulichen Datenbankspalten (mit Always Encrypted geschützt) entsprechen. Die Werte dieser Parameter werden dann vor der Übergabe an SQL Server oder Azure SQL-Datenbank verschlüsselt. Auf ähnliche Weise entschlüsselt der Treiber die Daten transparent, die von verschlüsselten Datenbankspalten in Abfrageergebnissen empfangen werden. Weitere Informationen finden Sie unter Always Encrypted (Cliententwicklung) und Entwickeln von Anwendungen mithilfe von Always Encrypted mit Secure Enclaves.

Hinweis

.NET Framework-Datenanbieter für SQL Server (System.Data.SqlClient) unterstützt die Verwendung von VBS-Enklaven ohne Nachweis nicht.

Voraussetzungen

  • Konfigurieren Sie Always Encrypted in Ihrer Datenbank. Dies umfasst die Bereitstellung von Always Encrypted-Schlüsseln und die Einrichtung der Verschlüsselung für ausgewählte Datenbankspalten. Wenn Sie nicht bereits über eine Datenbank verfügen, für die Always Encrypted konfiguriert ist, befolgen Sie die Anweisungen im Tutorial: Erste Schritte mit Always Encrypted.
  • Weitere Voraussetzungen für die Verwendung von Always Encrypted mit Secure Enclaves finden Sie unter Entwickeln von Anwendungen mithilfe von Always Encrypted mit Secure Enclaves.
  • Stellen Sie sicher, dass .NET Framework, Version 4.6.1 oder höher, auf dem Entwicklungscomputer installiert ist. Weitere Informationen finden Sie unter .NET Framework 4.6. Sie müssen auch sicherstellen, dass .NET Framework, Version 4.6 oder höher, als .NET Framework-Zielversion in der Entwicklungsumgebung konfiguriert ist. Wenn Sie Visual Studio verwenden, lesen Sie "How to: Target a Version of the .NET Framework".

Hinweis

Der Grad der Unterstützung für Always Encrypted in bestimmten Versionen von .NET Framework variiert. Immer verschlüsselte API-Verweise werden in den folgenden Abschnitten aufgeführt.

Aktivieren von Always Encrypted für Anwendungsabfragen

Die einfachste Möglichkeit zum Aktivieren der Verschlüsselung von Parametern und der Entschlüsselung von Abfrageergebnissen, die auf verschlüsselte Spalten ausgerichtet sind, besteht im Festlegen des Werts für das Kennwort der Verbindungszeichenfolge der Spaltenverschlüsselungseinstellung auf Aktiviert.

Im Folgenden finden Sie ein Beispiel für eine Verbindungszeichenfolge, die „Always Encrypted“ aktiviert:

string connectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true; Column Encryption Setting=enabled";
SqlConnection connection = new SqlConnection(connectionString);

Im Folgenden finden Sie auch ein gleichwertiges Beispiel, das die SqlConnectionStringBuilder.ColumnEncryptionSetting-Eigenschaft verwendet.

SqlConnectionStringBuilder strbldr = new SqlConnectionStringBuilder();
strbldr.DataSource = "server63";
strbldr.InitialCatalog = "Clinic";
strbldr.IntegratedSecurity = true;
strbldr.ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Enabled;
SqlConnection connection = new SqlConnection(strbldr.ConnectionString);

Always Encrypted kann auch für einzelne Abfragen aktiviert werden. Weitere Informationen finden Sie unten in Kontrollieren der Auswirkungen von Always Encrypted auf die Leistung . Die Aktivierung von Always Encrypted ist für eine erfolgreiche Verschlüsselung und Entschlüsselung nicht ausreichend. Sie müssen auch Folgendes sicherstellen:

  • Die Anwendung verfügt über die Datenbankberechtigungen VIEW ANY COLUMN MASTER KEY DEFINITION und VIEW ANY COLUMN ENCRYPTION KEY DEFINITION , die für den Zugriff auf die Metadaten in der Datenbank über Always Encrypted-Schlüssel erforderlich sind. Weitere Informationen finden Sie unter Abschnitt „Berechtigungen“ in Always Encrypted (Datenbank-Engine).
  • Die Anwendung kann auf den Hauptschlüssel der Spalte zugreifen, der die Spaltenverschlüsselungsschlüssel schützt, mit denen die abgefragten Datenbankspalten verschlüsselt werden.

Aktivieren von Always Encrypted mit Secure Enclaves

Ab .NET Framework Version 4.7.2 unterstützt der Treiber Always Encrypted mit Secure Enclaves.

Allgemeine Informationen zur Clienttreiberrolle in Enclave-Berechnungen und im Enclave-Nachweis finden Sie unter Entwickeln von Anwendungen mithilfe von Always Encrypted mit Secure Enclaves.

Konfigurieren der Anwendung:

  1. Aktivieren Sie Always Encrypted für Ihre Anwendungsabfragen, wie im vorherigen Abschnitt erläutert.

  2. Integrieren Sie das NuGet-Paket Microsoft.SqlServer.Management.AlwaysEncrypted.EnclaveProviders in Ihre Anwendung. NuGet ist eine Bibliothek von Enclave-Anbietern, die die clientseitige Logik für Nachweisprotokolle und für die Einrichtung eines sicheren Kanals mit einer Secure Enclave implementieren.

  3. Aktualisieren Sie die Anwendungskonfiguration (z. B. in „web.config“ oder „app.config“), um die Zuordnung zwischen einem für Ihre Datenbank konfigurierten Enclave-Typ und einem Enclave-Anbieter zu definieren.

    1. Wenn Sie SQL Server und Host Guardian Service (HGS) verwenden, müssen Sie den VBS-Enklaventyp dem Microsoft.SqlServer.Management.AlwaysEncrypted.EnclaveProviders.HostGuardianServiceEnclaveProvider-Klasse aus dem NuGet-Paket zuordnen.
    2. Wenn Sie Azure SQL-Datenbank und Microsoft Azure-Nachweis verwenden, müssen Sie den SGX-Enklaventyp dem Microsoft.SqlServer.Management.AlwaysEncrypted.EnclaveProviders.AzureAttestationEnclaveProvider-Klasse aus dem NuGet-Paket zuordnen.

    Ausführliche Anweisungen zum Bearbeiten Ihrer Anwendungskonfiguration finden Sie im Lernprogramm: Entwickeln einer .NET Framework-Anwendung mit Always Encrypted with secure Enklaven.

  4. Legen Sie das Enclave Attestation URL-Schlüsselwort in der Datenbankverbindungszeichenfolge auf eine Nachweis-URL (einen Nachweisdienstendpunkt) fest. Sie benötigen für Ihre Umgebung eine Nachweis-URL von dem Dienstadministrator, der für Nachweise zuständig ist.

    1. Wenn Sie SQL Server und den Host-Überwachungsdienst verwenden, finden Sie weitere Informationen unter Ermitteln und Freigeben der HGS-Nachweis-URL.
    2. Wenn Sie Azure SQL-Datenbank und Microsoft Azure Attestation verwenden, finden Sie weitere Informationen unter Ermitteln der Nachweis-URL für Ihre Nachweisrichtlinie.

Ein schrittweises Lernprogramm finden Sie im Lernprogramm: Entwickeln einer .NET Framework-Anwendung mit Always Encrypted mit sicheren Enklaven

Abrufen und Ändern von Daten in verschlüsselten Spalten

Nachdem Sie Always Encrypted für Anwendungsabfragen aktiviert haben, können Sie mithilfe der standardmäßigen ADO.NET-APIs (siehe Abrufen und Ändern von Daten in ADO.NET) oder der APIs für .NET Framework-Datenanbieter für SQL Server , die im System.Data.SqlClient-Namespacedefiniert sind, die Daten in verschlüsselten Datenbankspalten abrufen oder ändern. Vorausgesetzt, dass Ihre Anwendung über die erforderlichen Datenbankberechtigungen verfügt und auf den Hauptschlüssel für die Spalte zugreifen kann, verschlüsselt der .NET Framework-Datenanbieter für SQL Server alle Abfrageparameter, die auf verschlüsselte Spalten ausgerichtet sind, und entschlüsselt die Daten, die von verschlüsselten Spalten abgerufen wurden, die Klartextwerte von .NET-Typen zurückgeben, die den SQL Server-Datentypen entsprechen, die für die Spalten im Datenbankschema festgelegt wurden. Wenn Always Encrypted nicht aktiviert ist, tritt bei Abfragen mit Parametern, die verschlüsselte Spalten anzielen, ein Fehler auf. Abfragen können weiterhin Daten aus verschlüsselten Spalten abrufen, solange die Abfrage keine Parameter für verschlüsselte Spalten enthält. Die .NET Framework-Datenanbieter für SQL Server versuchen jedoch nicht, die aus verschlüsselten Spalten abgerufenen Werte zu entschlüsseln, daher erhält die Anwendung binär verschlüsselte Daten (als Bytearrays).

Die folgende Tabelle fasst das Verhalten von Abfragen in Abhängigkeit davon zusammen, ob Always Encrypted aktiviert ist:

Abfragemerkmal Always Encrypted ist aktiviert und die Anwendung kann auf die Schlüssel und Schlüsselmetadaten zugreifen. Always Encrypted ist aktiviert, und die Anwendung kann nicht auf die Schlüssel oder Schlüsselmetadaten zugreifen. Always Encrypted ist deaktiviert
Abfragen mit Parametern, die auf verschlüsselte Spalten ausgerichtet sind. Parameterwerte werden transparent verschlüsselt. Fehler Fehler
Abfragen, die Daten von verschlüsselten Spalten ohne Parameter abrufen, die auf verschlüsselte Spalten ausgerichtet sind. Ergebnisse von verschlüsselten Spalten werden transparent entschlüsselt. Die Anwendung erhält Klartextwerte der .NET-Datentypen, die den SQL Server-Datentypen entsprechen, die für die verschlüsselten Spalten konfiguriert wurden. Fehler Ergebnisse von verschlüsselten Spalten werden nicht entschlüsselt. Die Anwendung erhält verschlüsselte Werte als Bytearrays (byte[]).

Die folgenden Beispiele veranschaulichen das Abrufen und Ändern von Daten in verschlüsselten Spalten. Die Beispiele gehen von der Zieltabelle mit folgendem Schema aus. Die Spalten „SSN“ und „BirthDate“ werden verschlüsselt.

CREATE TABLE [dbo].[Patients]([PatientId] [int] IDENTITY(1,1), 
 [SSN] [char](11) COLLATE Latin1_General_BIN2 
 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, 
 ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', 
 COLUMN_ENCRYPTION_KEY = CEK1) NOT NULL,
 [FirstName] [nvarchar](50) NULL,
 [LastName] [nvarchar](50) NULL, 
 [BirthDate] [date] 
 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, 
 ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', 
 COLUMN_ENCRYPTION_KEY = CEK1) NOT NULL
 PRIMARY KEY CLUSTERED ([PatientId] ASC) ON [PRIMARY])
 GO

Beispiel zum Einfügen von Daten

In diesem Beispiel wird eine Zeile in die Tabelle „Patients“ eingefügt. Beachten Sie Folgendes:

  • Es erfolgt keine spezielle Verschlüsselung im Beispielcode. Der .NET Framework-Datenanbieter für SQL Server erkennt und verschlüsselt die Parameter paramSSN und paramBirthdate automatisch, die auf verschlüsselte Spalten ausgerichtet sind. Dadurch wird die Verschlüsselung für die Anwendung transparent.
  • Die in die Datenbankspalten eingefügten Werte, einschließlich der verschlüsselten Spalten, werden als SqlParameter -Objekte übergeben. Während die Verwendung von SqlParameter optional ist, wenn Werte an nicht verschlüsselte Spalten gesendet werden (obwohl sie dringend empfohlen wird, da sie dabei hilft, eine SQL-Einschleusung zu verhindern), ist sie für Werte erforderlich, die auf verschlüsselte Spalten ausgerichtet sind. Wenn die in den Spalten "SSN" oder "BirthDate" eingefügten Werte als Literale übergeben wurden, die in die Abfrageanweisungen eingebettet sind, schlägt die Abfrage fehl, da der .NET Framework-Datenanbieter für SQL Server die Werte in den verschlüsselten Zielspalten nicht ermitteln kann, sodass sie die Werte nicht verschlüsseln würde. Daher würde der Server sie zurückweisen, da sie mit den verschlüsselten Spalten inkompatibel sind.
  • Der auf die Spalte „SSN“ ausgerichtete Datentyp des Parameters wird auf eine ANSI-Zeichenfolge (Nicht-Unicode) festgelegt, der dem SQL Server-Datentyp „char/varchar“ zuordnet wird. Wenn der Typ des Parameters eine Unicode-Zeichenfolge (String) ist, die „nchar/nvarchar“ zugeordnet wird, würde bei der Abfrage ein Fehler auftreten, da Always Encrypted keine Konvertierungen von verschlüsselten „nchar/nvarchar“-Werten in verschlüsselte „char/narchar“-Werte unterstützt. Weitere Informationen zu den Datentypzuordnungen finden Sie unter SQL Server-Datentypzuordnungen .
  • Der Datentyp des in die Spalte „BirthDate“ eingefügten Parameters wird mithilfe der SqlParameter.SqlDbType-Eigenschaft explizit auf den SQL Server-Datentyp festgelegt, anstatt auf die implizite Zuordnung von .NET-Typen zu vertrauen, die bei der Verwendung der SqlParameter.DbType-Eigenschaft angewendet werden. Standardmäßig wird DateTime Structure dem SQL Server-Datentyp „datetime“ zugeordnet. Da der Datentyp der Spalte "Geburtsdatum" das Datum ist und "Always Encrypted" keine Konvertierung verschlüsselter Datetime-Werte in verschlüsselte Datumswerte unterstützt, führt die Verwendung der Standardzuordnung zu einem Fehler.
string connectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true; Column Encryption Setting=enabled";
using (SqlConnection connection = new SqlConnection(strbldr.ConnectionString))
{
   using (SqlCommand cmd = connection.CreateCommand())
   {
      cmd.CommandText = @"INSERT INTO [dbo].[Patients] ([SSN], [FirstName], [LastName], [BirthDate]) VALUES (@SSN, @FirstName, @LastName, @BirthDate);";

      SqlParameter paramSSN = cmd.CreateParameter();
      paramSSN.ParameterName = @"@SSN";
      paramSSN.DbType = DbType.AnsiStringFixedLength;
      paramSSN.Direction = ParameterDirection.Input;
      paramSSN.Value = "795-73-9838";
      paramSSN.Size = 11;
      cmd.Parameters.Add(paramSSN);

      SqlParameter paramFirstName = cmd.CreateParameter();
      paramFirstName.ParameterName = @"@FirstName";
      paramFirstName.DbType = DbType.String;
      paramFirstName.Direction = ParameterDirection.Input;
      paramFirstName.Value = "Catherine";
      paramFirstName.Size = 50;
      cmd.Parameters.Add(paramFirstName);

      SqlParameter paramLastName = cmd.CreateParameter();
      paramLastName.ParameterName = @"@LastName";
      paramLastName.DbType = DbType.String;
      paramLastName.Direction = ParameterDirection.Input;
      paramLastName.Value = "Abel";
      paramLastName.Size = 50;
      cmd.Parameters.Add(paramLastName);

      SqlParameter paramBirthdate = cmd.CreateParameter();
      paramBirthdate.ParameterName = @"@BirthDate";
      paramBirthdate.SqlDbType = SqlDbType.Date;
      paramBirthdate.Direction = ParameterDirection.Input;
      paramBirthdate.Value = new DateTime(1996, 09, 10);
      cmd.Parameters.Add(paramBirthdate);

      cmd.ExecuteNonQuery();
   } 
}

Beispiel für das Abrufen von Nur-Text-Daten

Im folgenden Beispiel wird das Filtern von Daten auf Basis verschlüsselter Werte und das Abrufen von Klartextdaten aus verschlüsselten Spalten veranschaulicht. Beachten Sie Folgendes:

  • Der in der WHERE-Klausel zum Filtern der Spalte „SSN“ verwendete Wert muss mithilfe von „SqlParameter“ übergeben werden, damit ihn der .NET Framework-Datenanbieter für SQL Server vor dem Senden an die Datenbank transparent verschlüsseln kann.
  • Alle Werte werden vom Programm als Klartext ausgegeben, da der .NET Framework-Datenanbieter für SQL Server die aus den Spalten „SSN“ und „BirthDate“ abgerufenen Daten transparent entschlüsselt.

Hinweis

Abfragen können auf Spalten Übereinstimmungsvergleiche ausführen, wenn sie mittels deterministischer Verschlüsselung verschlüsselt sind. Weitere Informationen finden Sie im Abschnitt Auswählen der deterministischen oder zufälligen Verschlüsselung.

string connectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true; Column Encryption Setting=enabled";
    
using (SqlConnection connection = new SqlConnection(strbldr.ConnectionString))
 {
    using (SqlCommand cmd = connection.CreateCommand())
 {

 cmd.CommandText = @"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE SSN=@SSN";
 SqlParameter paramSSN = cmd.CreateParameter();
 paramSSN.ParameterName = @"@SSN";
 paramSSN.DbType = DbType.AnsiStringFixedLength;
 paramSSN.Direction = ParameterDirection.Input;
 paramSSN.Value = "795-73-9838";
 paramSSN.Size = 11;
 cmd.Parameters.Add(paramSSN);
 using (SqlDataReader reader = cmd.ExecuteReader())
 {
   if (reader.HasRows)
 {
 while (reader.Read())
 {
    Console.WriteLine(@"{0}, {1}, {2}, {3}", reader[0], reader[1], reader[2], ((DateTime)reader[3]).ToShortDateString());
 }

Beispiel zum Abrufen von verschlüsselten Daten

Wenn Always Encrypted nicht aktiviert ist, können Abfragen weiterhin Daten aus verschlüsselten Spalten abrufen, so lange die Abfrage keine Parameter für verschlüsselte Spalten enthält.

Im folgenden Beispiel wird das Abrufen von binär verschlüsselten Daten aus verschlüsselten Spalten veranschaulicht. Beachten Sie Folgendes:

  • Da Always Encrypted in der Verbindungszeichenfolge nicht aktiviert ist, gibt die Abfrage verschlüsselte Werte von „SSN“ und „BirthDate“ als Bytearrays zurück (das Programm konvertiert die Werte in Zeichenfolgen).
  • Eine Abfrage, die Daten aus verschlüsselten Spalten mit deaktiviertem Always Encrypted abruft, kann Parameter aufweisen, so lange keiner der Parameter auf eine verschlüsselte Spalte ausgerichtet ist. Die obige Abfrage filtert nach der Spalte „LastName“, die in der Datenbank nicht verschlüsselt ist. Wenn die Abfrage nach „SSN“ oder „BirthDate“ filtert, würde ein Fehler auftreten.
string connectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true";
                
using (SqlConnection connection = new SqlConnection(connectionString))
{
   connection.Open();
   using (SqlCommand cmd = connection.CreateCommand())
   {
      cmd.CommandText = @"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE [LastName]=@LastName";
      SqlParameter paramLastName = cmd.CreateParameter();
      paramLastName.ParameterName = @"@LastName";
      paramLastName.DbType = DbType.String;
      paramLastName.Direction = ParameterDirection.Input;
      paramLastName.Value = "Abel";
      paramLastName.Size = 50;
      cmd.Parameters.Add(paramLastName);
      using (SqlDataReader reader = cmd.ExecuteReader())
      {
         if (reader.HasRows)
         {
            while (reader.Read())
         {
         Console.WriteLine(@"{0}, {1}, {2}, {3}", BitConverter.ToString((byte[])reader[0]), reader[1], reader[2], BitConverter.ToString((byte[])reader[3]));
      }
   }
}

Vermeiden allgemeiner Probleme beim Abfragen von verschlüsselten Spalten

Dieser Abschnitt beschreibt die allgemeinen Kategorien von Fehlern bei der Abfrage verschlüsselter Spalten über .NET-Anwendungen sowie einige Grundsätze zum Vermeiden dieser Fehler.

Konvertierungsfehler durch nicht unterstützte Datentypen

Always Encrypted unterstützt einige Konvertierungen für verschlüsselte Datentypen. Eine ausführliche Liste der unterstützten Typkonvertierungen finden Sie unter Always Encrypted. Gehen Sie wie folgt vor, um Fehler bei Konvertierung des Datentyps zu vermeiden:

  • Legen Sie die Typen der auf die verschlüsselten Spalten ausgerichteten Parameter so fest, dass der SQL Server-Datentyp des Parameters genau dem Typ der Zielspalte entspricht, oder dass eine Konvertierung des SQL Server-Datentyps des Parameters in den Zieltyp der Spalte unterstützt wird. Sie können die gewünschte Zuordnung von .NET-Datentypen zu bestimmten SQL Server-Datentypen mithilfe der „SqlParameter.SqlDbType“-Eigenschaft erzwingen.
  • Überprüfen Sie, ob die Genauigkeit und Dezimalstellenanzahl von Parametern, die auf Spalten der SQL Server-Datentypen „decimal“ und „numeric“ ausgerichtet sind, mit der für die Zielspalte konfigurierten Genauigkeit und Dezimalstellenanzahl identisch sind.
  • Überprüfen Sie, ob die Genauigkeit von Parametern, die auf Spalten der SQL Server-Datentypen „datetime2“, „datetimeoffset“ oder „time“ ausgerichtet sind, in Abfragen, in denen Werte der Zielspalte geändert werden, nicht höher als die Genauigkeit für die Zielspalte ist.

Fehler aufgrund der Übergabe von Klartext anstelle von verschlüsselten Werten

Jeder Wert, der auf eine verschlüsselte Spalte ausgerichtet ist, muss in der Anwendung verschlüsselt werden. Ein Versuch, einen Klartextwert einzufügen bzw. zu ändern oder nach einem Klartextwert für eine verschlüsselte Spalte zu filtern, führt zu einem Fehler wie dem Folgenden:

System.Data.SqlClient.SqlException (0x80131904): Operand type clash: varchar is incompatible with varchar(8000) encrypted with (encryption_type = 'DETERMINISTIC', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'CEK_Auto1', column_encryption_key_database_name = 'Clinic') collation_name = 'SQL_Latin1_General_CP1_CI_AS'

Stellen Sie Folgendes sicher, um solche Fehler zu vermeiden:

  • Always Encrypted ist für Anwendungsabfragen aktiviert, die auf verschlüsselte Spalten ausgerichtet sind (für die Verbindungszeichenfolge oder im SqlCommand -Objekt für eine bestimmte Abfrage).
  • Sie verwenden „SqlParameter“ zum Senden von Daten, die auf verschlüsselte Spalten ausgerichtet sind. Das folgende Beispiel zeigt eine Abfrage, die falsch nach einem Literal bzw. einer Konstante einer verschlüsselten Spalte (SSN) filtert (anstatt das Literal innerhalb eines „SqlParameter“-Objekts zu übergeben).
using (SqlCommand cmd = connection.CreateCommand())
{
   cmd.CommandText = @"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE SSN='795-73-9838'";
cmd.ExecuteNonQuery();
}

Arbeiten mit Spaltenhauptschlüsselspeichern

Der .NET Framework-Datenanbieter für SQL Server muss zum Verschlüsseln eines Parameterwerts oder zum Entschlüsseln von Daten in Abfrageergebnissen einen Spaltenverschlüsselungsschlüssel erhalten, der für die Zielspalte konfiguriert ist. Spaltenverschlüsselungsschlüssel werden in der verschlüsselten Form in den Datenbankmetadaten gespeichert. Jeder Spaltenverschlüsselungsschlüssel weist einen entsprechenden Spaltenhauptschlüssel auf, mit dem der Spaltenverschlüsselungsschlüssel verschlüsselt wurde. Die Datenbankmetadaten speichern die Spaltenmasterschlüssel nicht und enthalten nur die Informationen zu einem Schlüsselspeicher, der einen bestimmten Spaltenmasterschlüssel und den Speicherort des Schlüssels im Schlüsselspeicher enthält.

Um einen Klartextwert eines Spaltenverschlüsselungsschlüssels zu erhalten, ruft der .NET Framework-Datenanbieter für SQL Server zunächst die Metadaten zum Spaltenverschlüsselungsschlüssel und seinen entsprechenden Spaltenhauptschlüssel ab. Dann verwendet er die Informationen in den Metadaten, um den Schlüsselspeicher zu kontaktieren, der den Spaltenhauptschlüssel enthält, und um den verschlüsselten Spaltenverschlüsselungsschlüssel zu entschlüsseln. Der .NET Framework-Datenanbieter für SQL Server kommuniziert mit einem Schlüsselspeicher, wobei ein Spaltenhauptschlüssel-Speicheranbieter verwendet wird, der eine Instanz einer Klasse darstellt, die von der Klasse SqlColumnEncryptionKeyStoreProvider abgeleitet wird.

Vorgang zum Abrufen eines Spaltenverschlüsselungsschlüssels:

  1. Wenn Always Encrypted für eine Abfrage aktiviert ist, ruft der .NET Framework-Datenanbieter für SQL Server transparent sys.sp_describe_parameter_encryption auf, um Verschlüsselungsmetadaten für Parameter abzurufen, die verschlüsselte Spalten zum Ziel haben, falls die Abfrage Parameter aufweist. Für verschlüsselte Daten, die in den Ergebnissen einer Abfrage enthalten sind, fügt SQL Server automatisch Verschlüsselungsmetadaten an. Die Informationen über den Spaltenhauptschlüssel umfassen:

    • Den Namen eines Schlüsselspeicheranbieters, in dem ein Schlüsselspeicher verkapselt ist, der den Spaltenhauptschlüssel enthält.
    • Den Schlüsselpfad, der den Speicherort des Spaltenhauptschlüssels im Schlüsselspeicher angibt.

    Die Informationen über den Spaltenverschlüsselungsschlüssel umfassen:

    • Den verschlüsselten Wert eines Spaltenverschlüsselungsschlüssels.
    • Der Name des Algorithmus, der verwendet wurde, um den CEK zu verschlüsseln.
  2. Der .NET Framework-Datenanbieter für SQL Server verwendet den Namen des Spaltenhauptschlüssel-Speicheranbieters, um das Anbieterobjekt (eine Instanz einer von der SqlColumnEncryptionKeyStoreProvider-Klasse abgeleiteten Klasse) in einer internen Datenstruktur nachzuschlagen.

  3. Um den Spaltenverschlüsselungsschlüssel zu entschlüsseln, ruft der.NET Framework-Datenanbieter für SQL Server die Methode SqlColumnEncryptionKeyStoreProvider.DecryptColumnEncryptionKey auf und übergibt den Spaltenhauptschlüsselpfad, den verschlüsselten Wert des Spaltenverschlüsselungsschlüssels und den Namen des Verschlüsselungsalgorithmus, der zum Erstellen des verschlüsselten Spaltenverschlüsselungsschlüssels verwendet wurde.

Verwenden integrierter Spaltenhauptschlüssel-Speicheranbieter

Der .NET Framework-Datenanbieter für SQL Server enthält die folgenden integrierten Spaltenhauptschlüssel-Speicheranbieter, die mit den bestimmten Anbieternamen vorab registriert wurden (um den Anbieter zu suchen).

Klasse BESCHREIBUNG Anbietername (Suche)
SqlColumnEncryptionCertificateStoreProvider-Klasse Ein Anbieter für den Windows-Zertifikatspeicher. MSSQL_CERTIFICATE_STORE
SqlColumnEncryptionCngProvider-Klasse

Hinweis: Dieser Anbieter ist in .NET Framework 4.6.1 und höheren Versionen verfügbar.
Ein Anbieter für einen Schlüsselspeicher, der die Microsoft Cryptography API unterstützt: Next Generation (CNG) API. Üblicherweise handelt es sich bei einem solchen Speicher um ein Hardwaresicherheitsmodul – ein physisches Gerät, das digitale Schlüssel schützt und verwaltet und die kryptografische Verarbeitung bereitstellt. MSSQL_CNG_STORE
SqlColumnEncryptionCspProvider-Klasse

Hinweis: Dieser Anbieter ist in .NET Framework 4.6.1 oder höheren Versionen verfügbar.
Ein Anbieter für einen Schlüsselspeicher, der die Microsoft Cryptography API (CAPI)unterstützt. Üblicherweise handelt es sich bei einem solchen Speicher um ein Hardwaresicherheitsmodul – ein physisches Gerät, das digitale Schlüssel schützt und verwaltet und die kryptografische Verarbeitung bereitstellt. MSSQL_CSP_PROVIDER

Sie müssen keine Anwendungscodeänderungen vornehmen, um diese Anbieter zu verwenden, beachten Sie jedoch Folgendes:

  • Sie (oder der Datenbankadministrator) müssen sicherstellen, dass der in den Metadaten des Spaltenhauptschlüssels konfigurierte Anbietername richtig ist und der Pfad des Spaltenhauptschlüssels dem Schlüsselpfadformat entspricht, das für einen angegebenen Anbieter gültig ist. Es wird empfohlen, die Schlüssel mithilfe von Tools wie SQL Server Management Studio zu konfigurieren. Diese generieren die gültigen Anbieternamen und Schlüsselpfade automatisch, wenn die Anweisung CREATE COLUMN MASTER KEY (Transact-SQL) ausgegeben wird. Weitere Informationen finden Sie unter Konfigurieren von Always Encrypted mithilfe von SQL Server Management Studio und Konfigurieren von Always Encrypted mithilfe von PowerShell.
  • Stellen Sie sicher, dass die Anwendung auf den Schlüssel im Schlüsselspeicher zugreifen kann. Dies kann das Gewähren des Zugriffs auf den Schlüssel und/oder Schlüsselspeicher für die Anwendung (abhängig vom Schlüsselspeicher) oder das Ausführen anderer wichtiger speicherspezifischer Konfigurationsschritte einbeziehen. Um beispielsweise auf einen Schlüsselspeicher zuzugreifen, der CNG oder CAPI implementiert (z. B. ein Hardwaresicherheitsmodul), müssen Sie sicherstellen, dass eine Bibliothek, die CNG oder CAPI für Ihren Speicher implementiert, auf Ihrem Anwendungscomputer installiert ist. Ausführliche Informationen finden Sie unter Erstellen und Speichern von Spaltenhauptschlüsseln für Always Encrypted.

Verwenden des Azure Key Vault-Anbieters

Azure Key Vault ist eine praktische Möglichkeit zum Speichern von Spaltenhauptschlüsseln für Always Encrypted (insbesondere, wenn Ihre Anwendungen in Azure gehostet werden). Der .NET Framework-Datenanbieter für SQL Server enthält keinen integrierten Hauptschlüsselspeicheranbieter für Azure Key Vault, ist aber als NuGet-Paket verfügbar, das Sie problemlos in Ihre Anwendung integrieren können. Einzelheiten dazu finden Sie unter:

Implementieren eines benutzerdefinierten Speicheranbieters für den Spaltenhauptschlüssel

Wenn Sie Spaltenmasterschlüssel in einem Schlüsselspeicher speichern möchten, der von einem vorhandenen Anbieter nicht unterstützt wird, können Sie einen benutzerdefinierten Anbieter implementieren, indem Sie die SqlColumnEncryptionCngProvider-Klasse erweitern und den Anbieter mithilfe der SqlConnection.RegisterColumnEncryptionKeyStoreProviders-Methode registrieren.

public class MyCustomKeyStoreProvider : SqlColumnEncryptionKeyStoreProvider
    {
        public override byte[] EncryptColumnEncryptionKey(string masterKeyPath, string encryptionAlgorithm, byte[] columnEncryptionKey)
        {
            // Logic for encrypting a column encrypted key.
        }
        public override byte[] DecryptColumnEncryptionKey(string masterKeyPath, string encryptionAlgorithm, byte[] EncryptedColumnEncryptionKey)
        {
            // Logic for decrypting a column encrypted key.
        }
    }  
    class Program
    {
        static void Main(string[] args)
        {
            Dictionary\<string, SqlColumnEncryptionKeyStoreProvider> providers =
               new Dictionary\<string, SqlColumnEncryptionKeyStoreProvider>();
            providers.Add("MY_CUSTOM_STORE", customProvider);
            SqlConnection.RegisterColumnEncryptionKeyStoreProviders(providers);
            providers.Add(SqlColumnEncryptionCertificateStoreProvider.ProviderName, customProvider);
            SqlConnection.RegisterColumnEncryptionKeyStoreProviders(providers); 
	   // ...
        }

    }

Verwenden von Spaltenhauptschlüssel-Speicheranbietern für die programmgesteuerte Schlüsselbereitstellung

Beim Zugriff auf verschlüsselte Spalten sucht der .NET Framework-Datenanbieter für SQL Server den richtigen Speicheranbieter für Spaltenhauptschlüssel transparent und ruft ihn anschließend auf, um die Spaltenverschlüsselungsschlüssel zu entschlüsseln. In der Regel ruft der normale Anwendungscode die Speicheranbieter für Spaltenhauptschlüssel nicht direkt auf. Sie können einen Anbieter jedoch explizit instanziieren und aufrufen, um Always Encrypted-Schlüssel programmgesteuert zum Generieren eines verschlüsselten Spaltenverschlüsselungsschlüssels und Entschlüsseln eines Spaltenverschlüsselungsschlüssels (z. B. im Rahmen einer Spaltenhauptschlüsselrotation) bereitzustellen und zu verwalten. Weitere Informationen finden Sie unter Übersicht über die Schlüsselverwaltung für Always Encrypted. Die Implementierung eigener Schlüsselverwaltungstools ist möglicherweise nur erforderlich, wenn Sie einen benutzerdefinierten Schlüsselspeicheranbieter verwenden. Bei der Verwendung von Schlüsseln, die in Schlüsselspeichern (für die integrierte Anbieter vorhanden sind) und/oder in Azure Key Vault gespeichert werden, können Sie vorhandene Tools wie SQL Server Management Studio oder PowerShell verwenden, um Schlüssel zu verwalten und bereitzustellen. Im folgenden Beispiel wird das Generieren eines Spaltenverschlüsselungsschlüssels und das Verwenden der SqlColumnEncryptionCertificateStoreProvider -Klasse zum Verschlüsseln des Schlüssels mit einem Zertifikat veranschaulicht.

using System.Security.Cryptography;
static void Main(string[] args)
{
    byte[] EncryptedColumnEncryptionKey = GetEncryptedColumnEncryptonKey(); 
    Console.WriteLine("0x" + BitConverter.ToString(EncryptedColumnEncryptionKey).Replace("-", "")); 
    Console.ReadKey();
}

static byte[]  GetEncryptedColumnEncryptonKey()
{
    int cekLength = 32;
    String certificateStoreLocation = "CurrentUser";
    String certificateThumbprint = "698C7F8E21B2158E9AED4978ADB147CF66574180";
    // Generate the plaintext column encryption key.
    byte[] columnEncryptionKey = new byte[cekLength];
    RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
    rngCsp.GetBytes(columnEncryptionKey);

    // Encrypt the column encryption key with a certificate.
    string keyPath = String.Format(@"{0}/My/{1}", certificateStoreLocation, certificateThumbprint);
    SqlColumnEncryptionCertificateStoreProvider provider = new SqlColumnEncryptionCertificateStoreProvider();
    return provider.EncryptColumnEncryptionKey(keyPath, @"RSA_OAEP", columnEncryptionKey); 
}

Kontrollieren der Auswirkungen von Always Encrypted auf die Leistung

Da Always Encrypted eine clientseitige Verschlüsselungstechnologie ist, werden die meisten Leistungseinbußen auf der Clientseite und nicht in der Datenbank beobachtet. Neben den Kosten für Verschlüsselungs- und Entschlüsselungsvorgänge ergeben sich die folgenden anderen Quellen für Leistungseinbußen auf der Clientseite:

  • Zusätzliche Roundtrips zur Datenbank zum Abrufen von Metadaten für Abfrageparameter.
  • Aufrufe an einen Spaltenhauptschlüsselspeicher für den Zugriff auf einen Spaltenhauptschlüssel.

In diesem Abschnitt werden die integrierten Leistungsoptimierungen im .NET Framework-Anbieter für SQL Server und die Steuerung der Auswirkung der beiden oben genannten Faktoren auf die Leistung beschrieben.

Kontrollieren von Roundtrips zum Abrufen von Metadaten für Abfrageparameter

Wenn Always Encrypted für eine Verbindung aktiviert ist, ruft der .NET Framework-Datenanbieter für SQL Server standardmäßig sys.sp_describe_parameter_encryption für jede parametrisierte Abfrage auf, wobei die Abfrageanweisung (ohne Parameterwerte) an SQL Server übergeben wird. Die Abfrageanweisung wird vonsys.sp_describe_parameter_encryption analysiert, um zu ermitteln, ob Parameter verschlüsselt werden müssen. In diesem Fall gibt sie die verschlüsselungsbezogenen Informationen zurück, die dem .NET Framework-Datenanbieter für SQL Server das Verschlüsseln von Parameterwerten ermöglichen. Das oben beschriebene Verhalten stellt ein hohes Maß an Transparenz für die Clientanwendung sicher. Die Anwendung (und der Anwendungsentwickler) muss nicht beachten, welche Abfragen Zugriff auf verschlüsselte Spalten haben, solange die auf verschlüsselte Spalten ausgerichteten Werte in SqlParameter-Objekten an den .NET Framework-Datenanbieter für SQL Server übergeben werden.

Zwischenspeichern von Abfragemetadaten

In .NET Framework 4.6.2 und höher speichert der .NET Framework-Datenanbieter für SQL Server die Ergebnisse von sys.sp_describe_parameter_encryption für jede Abfrageanweisung zwischen. Daher ruft der Treiber sys.sp_describe_parameter_encryption nur einmal auf, wenn die gleiche Abfrageanweisung mehrfach ausgeführt wird. Die Zwischenspeicherung von Verschlüsselungsmetadaten für Abfrageanweisungen verringert die Leistungskosten beim Abrufen von Metadaten bei der Datenbank erheblich. Die Zwischenspeicherung ist standardmäßig aktiviert. Sie können die Zwischenspeicherung von Parametermetadaten deaktivieren, indem Sie die Eigenschaft SqlConnection.ColumnEncryptionQueryMetadataCacheEnabled auf FALSCH festlegen; dies wird jedoch mit Ausnahme seltener Fälle, wie dem unten beschriebenen, nicht empfohlen:

Betrachten Sie eine Datenbank mit zwei verschiedenen Schemas: s1 und s2. Jedes Schema enthält eine Tabelle mit dem gleichen Namen: t. Die Definitionen der Tabellen s1.t und s2.t sind identisch, mit Ausnahme der verschlüsselungsbezogenen Eigenschaften: Eine Spalte mit dem Namen c ist in s1.t nicht verschlüsselt und in s2.t verschlüsselt. Die Datenbank weist zwei Benutzer auf, u1 und u2. Das Standardschema für Benutzer von u1 ist s1. Das Standardschema für u2 ist s2. Eine .NET-Anwendung öffnet zwei Verbindungen mit der Datenbank, mit der Identität des Benutzers u1 in der einen Verbindung und der des Benutzers u2 in der anderen Verbindung. Die Anwendung sendet eine Abfrage mit einem Parameter für die c Spalte über die Verbindung für den Benutzer u1 (die Abfrage gibt das Schema nicht an, sodass das Standardbenutzerschema angenommen wird). Anschließend sendet die Anwendung die gleiche Abfrage über die Verbindung für den Benutzer u2. Wenn die Zwischenspeicherung von Abfragemetadaten aktiviert ist, wird der Cache nach der ersten Abfrage mit Metadaten gefüllt, die die c Spalte angeben, die Abfrageparameterziele werden nicht verschlüsselt. Da die zweite Abfrage die gleiche Abfrageanweisung aufweist, werden die im Cache gespeicherten Informationen verwendet. Daher sendet der Treiber die Abfrage, ohne den Parameter zu verschlüsseln (was falsch ist, da die Zielspalte s2.t.c verschlüsselt ist), wodurch der Nur-Text-Wert des Parameters an den Server verloren geht. Der Server wird diese Inkompatibilität erkennen und den Treiber anweisen, den Cache zu aktualisieren, sodass die Anwendung die Abfrage transparent mit ordnungsgemäß verschlüsseltem Parameterwert erneut sendet. In einem solchen Fall sollte die Zwischenspeicherung deaktiviert werden, um die Offenlegung vertraulicher Werte gegenüber dem Server zu verhindern.

Festlegen von Always Encrypted auf Abfrageebene

Sie können Always Encrypted für einzelne Abfragen aktivieren, anstatt es für die Verbindung einzurichten, um beim Abrufen von Verschlüsselungsmetadaten für parametrisierte Abfragen die Auswirkung auf die Leistung zu steuern. Auf diese Weise können Sie sicherstellen, dass sys.sp_describe_parameter_encryption nur für Abfragen aufgerufen wird, bei denen Ihnen bekannt ist, dass sie über Parameter verfügen, die auf verschlüsselte Spalten ausgerichtet sind. Beachten Sie jedoch, dass Sie auf diese Weise die Transparenz der Verschlüsselung reduzieren: Wenn Sie die Verschlüsselungseigenschaften der Datenbankspalten ändern, müssen Sie möglicherweise den Code der Anwendung ändern, um ihn mit den Schemaänderungen auszurichten.

Hinweis

Das Festlegen von Always Encrypted auf der Abfrageebene führt in .NET 4.6.2 und späteren Versionen, in denen die Zwischenspeicherung von Metadaten für die Parameterverschlüsselung implementiert ist, zu leichten Leistungsvorteilen.

Sie müssen diesen Konstruktor von SqlCommand und SqlCommandColumnEncryptionSettingverwenden, um das Verhalten von Always Encrypted für einzelne Abfragen zu steuern. Hier sind einige nützliche Richtlinien:

  • Wenn die meisten Abfragen, die eine Clientanwendung über eine Datenbankverbindung sendet, auf verschlüsselte Spalten zugreifen:
    • Legen Sie für das Verbindungszeichenfolgen-Kennwort für Spaltenverschlüsselungseinstellung den Wert Aktiviertfest.
    • Legen Sie "SqlCommandColumnEncryptionSetting.Disabled " für einzelne Abfragen fest, die nicht auf verschlüsselte Spalten zugreifen. Dadurch werden sowohl der Aufruf von sys.sp_describe_parameter_encryption als auch der Versuch deaktiviert, Werte im Resultset zu entschlüsseln.
    • Legen Sie "SqlCommandColumnEncryptionSetting.ResultSet " für einzelne Abfragen fest, die keine Parameter erfordern, die Verschlüsselung erfordern, sondern Daten aus verschlüsselten Spalten abrufen. Dadurch werden der Aufruf von sys.sp_describe_parameter_encryption und die Parameterverschlüsselung deaktiviert. Die Abfrage ist in der Lage, die Ergebnisse von Spaltenverschlüsselungen zu entschlüsseln.
  • Wenn die meisten Abfragen, die eine Clientanwendung über eine Datenbankverbindung sendet, nicht auf verschlüsselte Spalten zugreifen:
    • Legen Sie für das Verbindungszeichenfolgen-Kennwort für Spaltenverschlüsselungseinstellung den Wert Deaktiviertfest.
    • Legen Sie SqlCommandColumnEncryptionSetting.Enabled für einzelne Abfragen mit Parametern fest, die verschlüsselt werden müssen. Dadurch werden sowohl der Aufruf von sys.sp_describe_parameter_encryption als auch die Entschlüsselung von Abfrageergebnissen aktiviert, die aus verschlüsselten Spalten abgerufen werden.
    • Legen Sie SqlCommandColumnEncryptionSetting.ResultSet für Abfragen fest, die keine Parameter besitzen, für die eine Verschlüsselung erforderlich ist, aber die Daten aus verschlüsselten Spalten abrufen. Dadurch werden der Aufruf von sys.sp_describe_parameter_encryption und die Parameterverschlüsselung deaktiviert. Die Abfrage ist in der Lage, die Ergebnisse von Spaltenverschlüsselungen zu entschlüsseln.

In dem folgenden Beispiel ist Always Encrypted für die Datenbankverbindung deaktiviert. Die Abfrage, die die Anwendung ausgibt, weist einen Parameter auf, der auf die spalte "LastName" ausgerichtet ist, die nicht verschlüsselt ist. Die Abfrage ruft Daten aus den Spalten „SSN“ und „BirthDate“ ab, die beide verschlüsselt sind. In diesem Fall ist das Aufrufen von sys.sp_describe_parameter_encryption nicht erforderlich, um Verschlüsselungsmetadaten abzurufen. Die Entschlüsselung der Abfrageergebnisse muss jedoch aktiviert sein, damit die Anwendung Klartextwerte aus den beiden verschlüsselten Spalten erhalten kann. Um dies sicherzustellen, wird die Einstellung „SqlCommandColumnEncryptionSetting.ResultSet-Einstellung“ verwendet.

string connectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true";
using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();
    using (SqlCommand cmd = new SqlCommand(@"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE [LastName]=@LastName",
connection, null, SqlCommandColumnEncryptionSetting.ResultSetOnly))
    {
        SqlParameter paramLastName = cmd.CreateParameter();
        paramLastName.ParameterName = @"@LastName";
        paramLastName.DbType = DbType.String;
        paramLastName.Direction = ParameterDirection.Input;
        paramLastName.Value = "Abel";
        paramLastName.Size = 50;
        cmd.Parameters.Add(paramLastName);
        using (SqlDataReader reader = cmd.ExecuteReader())
            {
               if (reader.HasRows)
               {
                  while (reader.Read())
                  {
                     Console.WriteLine(@"{0}, {1}, {2}, {3}", reader[0], reader[1], reader[2], ((DateTime)reader[3]).ToShortDateString());
                  }
               }
            }
  } 
}

Zwischenspeicherung von Spaltenverschlüsselungsschlüsseln

Der .NET Framework-Datenanbieter für SQL Server speichert die Spaltenverschlüsselungsschlüssel im Klartext im Speicher zwischen, um die Anzahl der Aufrufe an einen Spaltenhauptschlüsselspeicher zu verringern. Nach dem Erhalt des Verschlüsselungsschlüsselwerts für die verschlüsselte Spalte von den Datenbankmetadaten versucht der Treiber zunächst, den Spaltenverschlüsselungsschlüssel im Klartext zu finden, der dem verschlüsselten Schlüsselwert entspricht. Der Treiber ruft den Schlüsselspeicher mit dem Spaltenmasterschlüssel nur auf, wenn er den Wert des verschlüsselten Spaltenverschlüsselungsschlüssels im Cache nicht finden kann.

Hinweis

In .NET Framework 4.6 und 4.6.1 werden die Einträge für den Spaltenverschlüsselungsschlüssel niemals aus dem Cache entfernt. Dies bedeutet, dass der Treiber den Schlüsselspeicher für einen gegebenen verschlüsselten Spaltenverschlüsselungsschlüssel während der Lebensdauer der Anwendung nur einmal kontaktiert.

In .NET Framework 4.6.2 und höher werden die Cacheeinträge nach einer konfigurierbaren Gültigkeitsdauer aus Sicherheitsgründen zwangsweise entfernt. Der Standardwert für die Gültigkeitsdauer beträgt 2 Stunden. Wenn Sie strengere Anforderungen an die Dauer der Speicherung von unverschlüsselten Spaltenverschlüsselungsschlüsseln in der Anwendung haben, können Sie den Wert mithilfe der Eigenschaft SqlConnection.ColumnEncryptionKeyCacheTtländern.

Aktivieren von zusätzlichem Schutz für einen kompromittierten SQL Server

Standardmäßig verlässt sich der .NET Framework-Datenanbieter für SQL Server beim Bereitstellen von Metadaten über die in der Datenbank zu verschlüsselnden Spalten und die Art der Verschlüsselung auf das Datenbanksystem (SQL Server oder Azure SQL Database). Die Verschlüsselungsmetadaten ermöglichen dem .NET Framework-Datenanbieter für SQL Server das Verschlüsseln von Abfrageparametern und das Entschlüsseln von Abfrageergebnissen ohne irgendwelche Eingaben von der Anwendung, wodurch sich die Anzahl der in der Anwendung erforderlichen Änderungen erheblich reduziert. Wenn der SQL Server-Prozess jedoch gefährdet ist und ein Angreifer die Metadaten manipuliert, die von SQL Server an den .NET Framework-Datenanbieter für SQL Server gesendet werden, kann der Angreifer unter Umständen imstande sein, vertrauliche Informationen zu stehlen. In diesem Abschnitt werden APIs beschrieben, die das Bereitstellen einer zusätzlichen Schutzebene gegen diese Art von Angriff, jedoch auf Kosten geringerer Transparenz, unterstützen.

Erzwingen von Parameterverschlüsselung

Bevor der .NET Framework-Datenanbieter für SQL Server eine parametrisierte Abfrage an SQL Server sendet, bittet er SQL Server (durch Aufrufen von sys.sp_describe_parameter_encryption), die Abfrageanweisung zu analysieren und Informationen über die in der Abfrage zu verschlüsselnden Parameter bereitzustellen. Eine kompromittierte SQL Server-Instanz könnte den .NET Framework-Datenanbieter für SQL Server irreführen, indem die Metadaten gesendet werden, die angeben, dass der Parameter nicht auf eine verschlüsselte Spalte ausgerichtet ist, obwohl die Spalte in der Datenbank verschlüsselt ist. Daher würde der .NET Framework-Datenanbieter für SQL Server den Parameterwert nicht verschlüsseln und als Nur-Text an die kompromittierte SQL Server-Instanz senden.

Um einen derartigen Angriff zu verhindern, kann eine Anwendung die SqlParameter.ForceColumnEncryption -Eigenschaft für den Parameter auf WAHR festlegen. Dies führt dazu, dass der .NET Framework-Datenanbieter für SQL Server eine Ausnahme auslöst, wenn die vom Server empfangenen Metadaten angibt, dass der Parameter nicht verschlüsselt werden muss.

Die Eigenschaft SqlParameter.ForceColumnEncryption hilft zwar beim Verbessern der Sicherheit, jedoch verringert sie zugleich die Transparenz der Verschlüsselung für die Clientanwendung. Wenn Sie das Datenbankschema aktualisieren, um die Menge der verschlüsselten Spalten zu ändern, müssen Sie möglicherweise auch an der Anwendung Änderungen vornehmen.

Das folgende Codebeispiel zeigt die Verwendung der SqlParameter.ForceColumnEncryption .

SqlCommand cmd = _sqlconn.CreateCommand(); 

// Use parameterized queries to access Always Encrypted data. 
 
cmd.CommandText = @"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE [SSN] = @SSN;"; 

SqlParameter paramSSN = cmd.CreateParameter(); 
paramSSN.ParameterName = @"@SSN"; 
paramSSN.DbType = DbType.AnsiStringFixedLength; 
paramSSN.Direction = ParameterDirection.Input; 
paramSSN.Value = ssn; 
paramSSN.Size = 11; 
paramSSN.ForceColumnEncryption = true; 
cmd.Parameters.Add(paramSSN); 

SqlDataReader reader = cmd.ExecuteReader();

Konfigurieren von vertrauenswürdigen Spaltenmasterschlüsselpfaden

Die Verschlüsselungsmetadaten, die SQL Server für Abfrageparameter mit verschlüsselten Spalten als Ziel und für die aus verschlüsselten Spalten abgerufenen Ergebnisse zurückgibt, beinhalten den Schlüsselpfad des Spaltenhauptschlüssels, der den Schlüsselspeicher und den Speicherort des Schlüssels im Schlüsselspeicher angibt. Wenn die SQL Server-Instanz gefährdet ist, könnte sie den Schlüsselpfad, der den .NET Framework-Datenanbieter für SQL Server anweist, an den von einem Angreifer kontrollierten Speicherort senden. Dies kann zur Offenlegung der Anmeldeinformationen des Schlüsselspeichers führen, falls der Schlüsselspeicher die Authentifizierung der Anwendung vorschreibt.

Um solche Angriffe zu verhindern, kann die Anwendung die Liste der vertrauenswürdigen Schlüsselpfade für einen bestimmten Server mithilfe der Eigenschaft SqlConnection.ColumnEncryptionTrustedMasterKeyPathsfestlegen. Wenn der .NET Framework-Datenanbieter für SQL Server einen Schlüsselpfad empfängt, der nicht in der Liste der vertrauenswürdigen Schlüsselpfade aufgeführt ist, löst er eine Ausnahme aus.

Obwohl das Festlegen von vertrauenswürdigen Schlüsselpfaden die Sicherheit Ihrer Anwendung verbessert, müssen Sie den Code oder/und die Konfiguration der Anwendung ändern, wenn Sie den Spaltenmasterschlüssel drehen (wenn sich der Spaltenmasterschlüsselpfad ändert).

Das folgende Beispiel zeigt die Konfiguration von vertrauenswürdigen Spaltenhauptschlüsselpfaden:

// Configure trusted key paths to protect against fake key paths sent by a compromised SQL Server instance 
// First, create a list of trusted key paths for your server 
List<string> trustedKeyPathList = new List<string>(); 
trustedKeyPathList.Add("CurrentUser/my/425CFBB9DDDD081BB0061534CE6AB06CB5283F5Ea"); 

// Register the trusted key path list for your server 

SqlConnection.ColumnEncryptionTrustedMasterKeyPaths.Add(serverName, trustedKeyPathList);

Kopieren von verschlüsselten Daten mithilfe von „SqlBulkCopy“

Mit „SqlBulkCopy“ können Sie Daten, die bereits verschlüsselt sind und in einer Tabelle gespeichert werden, in eine andere Tabelle kopieren, ohne die Daten zu entschlüsseln. Gehen Sie dafür folgendermaßen vor:

  • Stellen Sie sicher, dass die Verschlüsselungskonfiguration der Zieltabelle mit der Konfiguration der Quelltabelle identisch ist. Insbesondere müssen für beide Tabellen dieselben Spalten verschlüsselt sein. Zudem müssen die Spalten mithilfe derselben Verschlüsselungstypen und mit denselben Verschlüsselungsschlüsseln verschlüsselt werden. Hinweis: Wenn eine der Zielspalten anders als die entsprechende Quellspalte verschlüsselt ist, können Sie die Daten in der Zieltabelle nach dem Kopiervorgang nicht entschlüsseln. Die Daten werden beschädigt.
  • Konfigurieren Sie beide Datenbankverbindungen, zur Quelltabelle und zur Zieltabelle, ohne Always Encrypted zu aktivieren.
  • Legen Sie die Option „AllowEncryptedValueModifications“ fest (siehe SqlBulkCopyOptions). Hinweis: Verwenden Sie Vorsicht, wenn Sie AllowEncryptedValueModifications angeben, da dies zu einer Beschädigung der Datenbank führen kann, da der .NET Framework-Datenanbieter für SQL Server nicht überprüft, ob die Daten tatsächlich verschlüsselt sind oder ob sie ordnungsgemäß mit demselben Verschlüsselungstyp, Algorithmus und Schlüssel wie die Zielspalte verschlüsselt ist.

Die Option „AllowEncryptedValueModifications“ ist in .NET Framework 4.6.1 und höheren Versionen verfügbar.

Hier finden Sie ein Beispiel, in dem Daten aus einer Tabelle in eine andere kopiert werden. Es wird angenommen, dass die Spalten „SSN“ und „BirthDate“ verschlüsselt sind.

static public void CopyTablesUsingBulk(string sourceTable, string targetTable)
{
   string sourceConnectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true";
   string targetConnectionString = "Data Source= server64; Initial Catalog=Clinic; Integrated Security=true";
   using (SqlConnection connSource = new SqlConnection(sourceConnectionString))
   {
      connSource.Open();
      using (SqlCommand cmd = new SqlCommand(string.Format("SELECT [PatientID], [SSN], [FirstName], [LastName], [BirthDate] FROM {0}", sourceTable), connSource))
      {
         using (SqlDataReader reader = cmd.ExecuteReader())
         {
            SqlBulkCopy copy = new SqlBulkCopy(targetConnectionString, SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.AllowEncryptedValueModifications);
            copy.EnableStreaming = true;
            copy.DestinationTableName = targetTable;
            copy.WriteToServer(reader);
         }
      }
}

„Immer verschlüsselt“ – API-Referenz

Namespace:System.Data.SqlClient

Assembly: System.Data (in System.Data.dll)

Name Beschreibung In .NET Version eingeführt
SqlColumnEncryptionCertificateStoreProvider-Klasse Ein Schlüsselspeicheranbieter für den Windows-Zertifikatspeicher. 4.6
SqlColumnEncryptionCngProvider-Klasse Eine Schlüsselspeicheranbieter für Microsoft Cryptography API: Next Generation (CNG). 4.6.1
SqlColumnEncryptionCspProvider-Klasse Eine Schlüsselspeicheranbieter für die auf der Microsoft CAPI basierenden Kryptografiedienstanbieter. 4.6.1
SqlColumnEncryptionKeyStoreProvider Die Basisklasse der Schlüsselspeicheranbieter. 4.6
SqlCommandColumnEncryptionSetting-Enumeration Einstellungen zum Aktivieren der Verschlüsselung und Entschlüsselung für eine Datenbankverbindung. 4.6
SqlConnectionColumnEncryptionSetting-Enumeration Einstellungen zum Steuern des Verhaltens von „Always Encrypted“ für einzelne Abfragen. 4.6
SqlConnectionStringBuilder.ColumnEncryptionSetting-Eigenschaft Ruft Always Encrypted in der Verbindungszeichenfolge ab und legt es fest. 4.6
SqlConnection.ColumnEncryptionQueryMetadataCacheEnabled Aktiviert und deaktiviert das Zwischenspeichern von Verschlüsselungsabfrage-Metadaten. 4.6.2
SqlConnection.ColumnEncryptionKeyCacheTtl Ruft die Gültigkeitsdauer für Einträge im Cache für den Spaltenverschlüsselungsschlüssel ab und legt diese fest. 4.6.2
SqlConnection.ColumnEncryptionTrustedMasterKeyPaths Ermöglicht Ihnen, eine Liste von vertrauenswürdigen Schlüsselpfaden für einen Datenbankserver festzulegen. Wenn der Treiber während der Verarbeitung einer Anwendungsabfrage einen Schlüsselpfad erhält, der nicht in der Liste enthalten ist, tritt bei der Abfrage ein Fehler auf. Diese Eigenschaft bietet zusätzlichen Schutz vor Angriffen, bei denen ein kompromittierter SQL Server gefälschte Schlüsselpfade bereitstellt, was zur Preisgabe der Anmeldeinformationen des Schlüsselspeichers führen kann. 4.6
SqlConnection.RegisterColumnEncryptionKeyStoreProviders-Methode Ermöglicht Ihnen, benutzerdefinierte Schlüsselspeicheranbieter zu registrieren. Dies ist ein Wörterbuch, das Anbieternamen von Schlüsselspeichern Implementierungen von Schlüsselspeicheranbietern zuordnet. 4.6
SqlCommand-Konstruktor (String, SqlConnection, SqlTransaction, SqlCommandColumnEncryptionSetting) Ermöglicht das Steuern des Verhaltens von „Always Encrypted“ für einzelne Abfragen. 4.6
SqlParameter.ForceColumnEncryption Erzwingt die Verschlüsselung eines Parameters. Wenn SQL Server den Treiber informiert, dass der Parameter nicht verschlüsselt werden muss, tritt bei der Abfrage, die diesen Parameter verwendet, ein Fehler auf. Diese Eigenschaft bietet zusätzlichen Schutz vor Angriffen, bei denen ein kompromittierter SQL Server dem Client falsche Verschlüsselungsmetadaten bereitstellt, was zur Offenlegung von Daten führen kann. 4.6
Neues Verbindungszeichenfolgen -Schlüsselwort: Column Encryption Setting=enabled Aktiviert oder deaktiviert die „Always Encrypted“-Funktionalität für die Verbindung. 4.6

Siehe auch