Not
Åtkomst till denna sida kräver auktorisation. Du kan prova att logga in eller byta katalog.
Åtkomst till denna sida kräver auktorisation. Du kan prova att byta katalog.
Gäller för: .NET Framework
.NET .NET
Standard
Den här artikeln innehåller information om hur du utvecklar .NET-program med Always Encrypted eller Always Encrypted med säkra enklaver och Microsoft .NET Data Provider för SQL Server.
Always Encrypted gör att klientprogram kan kryptera känsliga data och aldrig avslöja data eller krypteringsnycklar till SQL Server eller Azure SQL Database. En Always Encrypted-aktiverad drivrutin, till exempel Microsoft .NET Data Provider för SQL Server, uppnår den här säkerheten genom att transparent kryptera och dekryptera känsliga data i klientprogrammet. Drivrutinen avgör automatiskt vilka frågeparametrar som motsvarar känsliga databaskolumner (skyddade med Always Encrypted) och krypterar värdena för dessa parametrar innan data skickas till servern. På samma sätt avkrypterar drivrutinen på ett transparent sätt data som hämtats från krypterade databaskolumner i förfrågningsresultat. Mer information finns i Utveckla program med Always Encrypted och Utveckla program med Always Encrypted med säkra enklaver.
Förutsättningar
- Konfigurera Always Encrypted i databasen. Den här processen omfattar etablering av Always Encrypted-nycklar och konfiguration av kryptering för valda databaskolumner. Om du inte redan har en databas med Always Encrypted konfigurerad följer du anvisningarna i Självstudie: Komma igång med Always Encrypted.
- Om du använder Always Encrypted med säkra enklaver kan du läsa Utveckla program med Always Encrypted med säkra enklaver för fler krav.
- Se till att den nödvändiga .NET-plattformen är installerad på utvecklingsdatorn. Med Microsoft.Data.SqlClient stöds funktionen Always Encrypted för både .NET Framework och .NET Core. Kontrollera att .NET Framework 4.6 eller senare, eller .NET Core 2.1 eller senare har konfigurerats som målversionen av .NET-plattformen i utvecklingsmiljön. Med Microsoft.Data.SqlClient version 2.1.0 och senare stöds funktionen Always Encrypted även för .NET Standard 2.0. Om du vill använda Always Encrypted med säkra enklaver krävs .NET Standard 2.1 . Om du vill använda VBS-enklaver utan attestering krävs Microsoft.Data.SqlClient version 4.1 eller senare. Om du använder Visual Studio kan du läsa Översikt över ramverksmål.
I följande tabell sammanfattas de .NET-plattformar som krävs för att använda Always Encrypted med Microsoft.Data.SqlClient.
| Stöd för Always Encrypted | Stöd för "Always Encrypted" med "Secure Enclave" | Målramverk | Microsoft.Data.SqlClient-version | Operativsystem |
|---|---|---|---|---|
| Yes | Yes | .NET Framework 4.6+ | 1.1.0+ | Windows |
| Yes | Yes | .NET Core 2.1+ | 2.1.0+1 | Windows, Linux, macOS |
| Yes | Nej | .NET Standard 2.0 | 2.1.0+ | Windows, Linux, macOS |
| Yes | Yes | .NET Standard 2.1+ | 2.1.0+ | Windows, Linux, macOS |
Anmärkning
1 Innan Microsoft.Data.SqlClient version 2.1.0 stöds Always Encrypted endast i Windows.
Aktivera Always Encrypted för programfrågor
Det enklaste sättet att aktivera kryptering av parametrar och dekryptering av frågeresultat för krypterade kolumner är genom att ange värdet för nyckelordet för anslutningssträngen Column Encryption Setting till aktiverat.
I följande exempel används en anslutningssträng som aktiverar Always Encrypted:
string connectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true; Column Encryption Setting=enabled";
SqlConnection connection = new SqlConnection(connectionString);
Följande kodfragment är ett motsvarande exempel med egenskapen SqlConnectionStringBuilder.ColumnEncryptionSetting.
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
builder.DataSource = "server63";
builder.InitialCatalog = "Clinic";
builder.IntegratedSecurity = true;
builder.ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Enabled;
SqlConnection connection = new SqlConnection(builder.ConnectionString);
connection.Open();
Always Encrypted kan också aktiveras för enskilda frågor. Se avsnittet Kontrollera prestandapåverkan för Always Encrypted nedan. Det räcker inte att aktivera Always Encrypted för att kryptering eller dekryptering ska lyckas. Du måste också se till att:
- Applikationen har behörigheterna VIEW ANY COLUMN MASTER KEY DEFINITION och VIEW ANY COLUMN ENCRYPTION KEY DEFINITION, vilka krävs för att få åtkomst till metadata om Always Encrypted nycklar i databasen. Mer information finns i avsnittet Databasbehörigheter i Always Encrypted (Databasmotor).
- Programmet kan komma åt kolumnhuvudnyckeln som skyddar kolumnkrypteringsnycklarna, som krypterar de efterfrågade databaskolumnerna.
Aktivera Always Encrypted med säkra enklaver
Från och med Microsoft.Data.SqlClient version 1.1.0 stöder drivrutinen Always Encrypted med säkra enklaver.
Allmän information om hur du utvecklar program med enklaver finns i Utveckla program med Always Encrypted med säkra enklaver.
Om du vill aktivera enklaverberäkningar för en databasanslutning måste du ange följande nyckelord för anslutningssträngen, förutom att aktivera Always Encrypted (enligt beskrivningen i föregående avsnitt):
Attestation Protocol– anger ett attesteringsprotokoll.- Om det här nyckelordet inte anges inaktiveras säkra enklaver i anslutningen.
- Om du använder SQL Server med virtualiseringsbaserade säkerhets enklaver (VBS) och Host Guardian Service (HGS) ska värdet för det här nyckelordet vara
HGS. - Om du använder Azure SQL Database med Intel SGX-enklaver och Microsoft Azure Attestation bör värdet för det här nyckelordet vara
AAS. - Om du använder Azure SQL Database eller SQL Server med VBS-enklaver och vill avstå från attestering ska värdet för det här nyckelordet vara
None. Kräver version 4.1 eller senare.
Anmärkning
"Ingen" (ingen attestering) är det enda alternativet som för närvarande stöds för VBS-enklaver i Azure SQL Database.
Enclave Attestation URL– anger en attesterings-URL (en attesteringstjänstslutpunkt). Du måste hämta en attesterings-URL för din miljö från administratören för attesteringstjänsten.- Om du använder SQL Server och Host Guardian Service (HGS) kan du läsa Fastställa och dela HGS-attesterings-URL:en.
- Om du använder Azure SQL Database och Microsoft Azure Attestation kan du läsa Fastställ attesterings-URL för din attesteringsprincip.
- Om du använder
Noneattesteringsprotokollet krävs ingen attesterings-URL.
En stegvis självstudiekurs finns i Självstudie: Utveckla ett .NET-program med Always Encrypted med säkra enklaver.
Hämta och ändra data i krypterade kolumner
När du aktiverar Always Encrypted för programfrågor kan du använda sqlClient-standard-API:er (se Hämta och ändra data i ADO.NET) eller Microsoft .NET Data Provider för SQL Server-API :er, definierade i namnområdet Microsoft.Data.SqlClient, för att hämta eller ändra data i krypterade databaskolumner. Om ditt program har nödvändiga databasbehörigheter och kan komma åt kolumnhuvudnyckeln krypterar Microsoft .NET Data Provider för SQL Server alla frågeparametrar som riktar sig mot krypterade kolumner och dekrypterar data som hämtats från krypterade kolumner och returnerar oformaterade värden för .NET-typer som motsvarar de SQL Server-datatyper som angetts för kolumnerna i databasschemat. Om Always Encrypted inte är aktiverat misslyckas frågor med parametrar som riktar sig mot krypterade kolumner. Frågor kan fortfarande hämta data från krypterade kolumner så länge frågan inte har några parametrar för krypterade kolumner. Microsoft .NET Data Provider för SQL Server försöker dock inte dekryptera några värden som hämtats från krypterade kolumner och programmet tar emot binära krypterade data (som bytematriser).
I följande tabell sammanfattas beteendet för frågor, beroende på om Always Encrypted är aktiverat eller inte:
| Frågeegenskaper | Always Encrypted är aktiverat och programmet kan komma åt nycklar och nyckelmetadata | Always Encrypted är aktiverat och programmet kan inte komma åt nycklar eller nyckelmetadata | Always Encrypted är inaktiverat |
|---|---|---|---|
| Frågor med parametrar som riktar sig till krypterade kolumner. | Parametervärden krypteras transparent. | Error | Error |
| Frågor som hämtar data från krypterade kolumner utan parametrar som riktar sig mot krypterade kolumner. | Resultat från krypterade kolumner dekrypteras transparent. Programmet tar emot oformaterade värden för .NET-datatyper som motsvarar de SQL Server-typer som konfigurerats för de krypterade kolumnerna. | Error | Resultat från krypterade kolumner dekrypteras inte. Programmet tar emot krypterade värden som bytematriser (byte[]). |
I följande exempel visas hur du hämtar och ändrar data i krypterade kolumner. Exemplen förutsätter att måltabellen har schemat nedan. Kolumnerna SSN och BirthDate krypteras.
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
Infoga ett dataexempel
I det här exemplet infogas en rad i tabellen Patienter. Observera följande information:
- Det finns inget specifikt för kryptering i exempelkoden.
Microsoft .NET Data Provider för SQL Server identifierar och krypterar automatiskt parametrarna
paramSSNochparamBirthdatesom riktar sig mot krypterade kolumner. Det här beteendet gör kryptering transparent för programmet. - Värdena som infogas i databaskolumner, inklusive de krypterade kolumnerna, skickas som SqlParameter-objekt . Att använda SqlParameter är valfritt när du skickar värden till icke-krypterade kolumner (även om det rekommenderas starkt eftersom det hjälper till att förhindra SQL-injektion). Det krävs dock för värden som är avsedda för krypterade kolumner. Om värdena som infogats i kolumnerna
SSNellerBirthDateskickades som literaler inbäddade i frågeutsatsen skulle frågan misslyckas eftersom Microsoft .NET Data Provider för SQL Server inte skulle kunna fastställa värdena i målkrypterade kolumner, så det skulle inte kryptera värdena. Därför skulle servern avvisa dem som inkompatibla med de krypterade kolumnerna. - Datatypen för parametern som riktar sig till
SSNkolumnen är inställd på en ANSI-sträng (icke-Unicode), som mappar till datatypen char/varchar SQL Server. Om parametertypen har angetts till en Unicode-sträng (sträng), som mappar till nchar/nvarchar, skulle frågan misslyckas eftersom Always Encrypted inte stöder konverteringar från krypterade nchar/nvarchar-värden till krypterade tecken/varchar-värden. Mer information om datatypsmappningar finns i SQL Server-datatypsmappningar . - Datatypen för parametern som infogas i
BirthDatekolumnen anges uttryckligen till SQL Server-måldatatypen med egenskapen SqlParameter.SqlDbType, i stället för att förlita sig på implicit mappning av .NET-typer till SQL Server-datatyper som används när du använder egenskapen SqlParameter.DbType. Som standard mappar DateTime Structure till datatypen datetime SQL Server. Eftersom datatypen förBirthDatekolumnen är datum och Always Encrypted inte stöder en konvertering av krypterade datetime-värden till krypterade datumvärden, skulle standardmappningen resultera i ett fel.
string connectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true; Column Encryption Setting=enabled";
using (SqlConnection connection = new SqlConnection(builder.ConnectionString))
using (SqlCommand cmd = connection.CreateCommand())
{
connection.Open();
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();
}
Hämtar exempel på klartextdata
I följande exempel visas filtrering av data baserat på krypterade värden och hämtning av klartextdata från krypterade kolumner.
string connectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true; Column Encryption Setting=enabled";
using (SqlConnection connection = new SqlConnection(builder.ConnectionString))
using (SqlCommand cmd = connection.CreateCommand())
{
connection.Open();
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());
}
}
}
}
Anmärkning
Värdet som används i WHERE-satsen för att filtrera på
SSNkolumnen måste skickas med hjälp av SqlParameter, så att Microsoft .NET Data Provider för SQL Server transparent kan kryptera den innan den skickas till databasen.Alla värden som skrivs ut av programmet är i klartext eftersom Microsoft .NET Data Provider för SQL Server transparent dekrypterar data som hämtas från kolumnerna
SSNochBirthDate.Frågor kan utföra likhetsjämförelser på kolumner om de krypteras med deterministisk kryptering.
Exempel på hämtning av krypterade data
Om Always Encrypted inte är aktiverat kan en fråga fortfarande hämta data från krypterade kolumner, så länge frågan inte har några parametrar för krypterade kolumner.
I följande exempel visas hur du hämtar binära krypterade data från krypterade kolumner.
string connectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true";
using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand cmd = connection.CreateCommand())
{
connection.Open();
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]));
}
}
}
}
Anmärkning
Eftersom Always Encrypted inte är aktiverat i anslutningssträngen returnerar frågan krypterade värden för
SSNochBirthDatesom bytematriser (programmet konverterar värdena till strängar).En fråga som hämtar data från krypterade kolumner med Always Encrypted inaktiverad kan ha parametrar, så länge ingen av parametrarna riktar sig mot en krypterad kolumn. Ovanstående fråga filtreras efter LastName, som inte är krypterad i databasen. Om frågan filtreras efter
SSNellerBirthDatemisslyckas frågan.
Undvik vanliga problem vid frågor om krypterade kolumner
I det här avsnittet beskrivs vanliga felkategorier när du kör frågor mot krypterade kolumner från .NET-program och några riktlinjer för hur du undviker dem.
Konverteringsfel av datatyp som inte stöds
Always Encrypted stöder få konverteringar för krypterade datatyper. Se Always Encrypted för en detaljerad lista över typkonverteringar som stöds. Gör följande för att undvika datatypkonverteringsfel:
- Ange vilka typer av parametrar som ska riktas mot krypterade kolumner så att SQL Server-datatypen för parametern antingen är exakt samma som typen av målkolumn eller en konvertering av SQL Server-datatypen för parametern till måltypen för kolumnen stöds. Du kan använda önskad mappning av .NET-datatyper till specifika SQL Server-datatyper med hjälp av egenskapen SqlParameter.SqlDbType.
- Kontrollera att precisionen och skalan för parametrar som riktar sig mot kolumner för decimal- och numeriska SQL Server-datatyper är samma som precisionen och skalan som konfigurerats för målkolumnen.
- Kontrollera att precisionen för parametrar som riktar sig till kolumner med datetime2, datetimeoffset eller tidpunkten för SQL Server-datatyper inte är större än precisionen för målkolumnen (i frågor som ändrar värden i målkolumnen).
Fel som beror på att klartext skickas i stället för krypterade värden
Alla värden som är inriktade på en krypterad kolumn måste krypteras i programmet. Ett försök att infoga/ändra eller filtrera efter ett oformaterat värde i en krypterad kolumn resulterar i ett fel som det här:
Microsoft.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'
Om du vill förhindra sådana fel kontrollerar du att:
- Always Encrypted är aktiverat för programfrågor som riktar sig till krypterade kolumner (för anslutningssträngen eller i SqlCommand-objektet för en specifik fråga).
- Du använder SqlParameter för att skicka data som riktar sig mot krypterade kolumner. I följande exempel visas en fråga som felaktigt filtreras av en literal/konstant på en krypterad kolumn (SSN) i stället för att skicka literalen inuti ett SqlParameter-objekt.
using (SqlCommand cmd = connection.CreateCommand())
{
cmd.CommandText = @"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE SSN = '795-73-9838'";
cmd.ExecuteNonQuery();
}
Arbeta med masternyckellagringar för kolumner
För att kryptera ett parametervärde eller dekryptera data i frågeresultat måste Microsoft .NET Data Provider för SQL Server hämta en kolumnkrypteringsnyckel som har konfigurerats för målkolumnen. Kolumnkrypteringsnycklar lagras i krypterad form i databasmetadata. Varje kolumnkrypteringsnyckel har en motsvarande kolumnhuvudnyckel som användes för att kryptera kolumnkrypteringsnyckeln. Databasmetadata lagrar inte kolumnhuvudnycklarna – den innehåller bara information om ett nyckelarkiv som innehåller en viss kolumnhuvudnyckel och platsen för nyckeln i nyckelarkivet.
För att få ett klartextvärde för en kolumnkrypteringsnyckel hämtar Microsoft .NET Data Provider för SQL Server först metadata om både kolumnkrypteringsnyckeln och dess motsvarande kolumnhuvudnyckel. Sedan används informationen i metadata för att kontakta nyckelarkivet som innehåller kolumnhuvudnyckeln och för att dekryptera krypteringsnyckeln för krypterad kolumn. Microsoft .NET-dataprovidern för SQL Server kommunicerar med ett nyckellager med hjälp av en kolumnnyckellagringsprovider – vilket är en instans av en klass som härleds från klassen SqlColumnEncryptionKeyStoreProvider.
Processen för att hämta en kolumnkrypteringsnyckel:
Om Always Encrypted är aktiverat för en fråga anropar Microsoft .NET Data Provider för SQL Server på ett transparent sätt sys.sp_describe_parameter_encryption för att hämta krypteringsmetadata för parametrar som riktar sig till krypterade kolumner, om frågan innehåller parametrar. För krypterade data i resultatet av en fråga bifogar SQL Server automatiskt krypteringsmetadata. Informationen om kolumnhuvudnyckeln innehåller:
- Namnet på en nyckellagringsprovider som kapslar in ett nyckelarkiv som innehåller kolumnhuvudnyckeln.
- Nyckelsökvägen som anger platsen för kolumnhuvudnyckeln i nyckelarkivet.
Informationen om kolumnkrypteringsnyckeln innehåller:
- Det krypterade värdet för en kolumnkrypteringsnyckel.
- Namnet på algoritmen som användes för att kryptera kolumnkrypteringsnyckeln.
Microsoft .NET Data Provider för SQL Server använder namnet på kolumnnyckellagringsprovidern för att leta upp providerobjektet, som är en instans av en klass som härleds från klassen SqlColumnEncryptionKeyStoreProvider, i en intern datastruktur.
För att dekryptera kolumnkrypteringsnyckeln anropar
SqlColumnEncryptionKeyStoreProvider.DecryptColumnEncryptionKey()metoden, skickar kolumnhuvudnyckelsökvägen, det krypterade värdet för kolumnkrypteringsnyckeln och namnet på krypteringsalgoritmen som används för att skapa den krypterade kolumnkrypteringsnyckeln.
Använda inbyggda huvudnyckellagringsprovider för kolumner
Microsoft .NET Data Provider för SQL Server levereras med följande inbyggda huvudnyckellagringsprovider för kolumner, som är förregistrerade med de specifika providernamnen (används för att leta upp providern). Dessa inbyggda nyckellagringsleverantörer stöds endast i Windows.
| Class | Description | Providernamn (sökning) | Platform |
|---|---|---|---|
| SqlColumnEncryptionCertificateStoreProvider-klass | Leverantör för Windows certifikatlagret. | MSSQL_CERTIFICATE_STORE | Windows |
| SqlColumnEncryptionCngProvider-klass | En provider för ett nyckelarkiv som har stöd för Microsoft Cryptography API: Next Generation (CNG) API. Vanligtvis är ett lager av den här typen en maskinvarusäkerhetsmodul – en fysisk enhet som skyddar och hanterar digitala nycklar och tillhandahåller krypteringsbearbetning. | MSSQL_CNG_STORE | Windows |
| SqlColumnEncryptionCspProvider-klass | En provider för ett nyckelarkiv som stöder Microsoft Cryptography API (CAPI). Vanligtvis är ett lager av den här typen en maskinvarusäkerhetsmodul – en fysisk enhet som skyddar och hanterar digitala nycklar och tillhandahåller krypteringsbearbetning. | MSSQL_CSP_PROVIDER | Windows |
Du behöver inte göra några ändringar i programkoden för att använda dessa leverantörer, men observera följande information:
- Du (eller din DBA) måste se till att providernamnet, som konfigurerats i kolumnens huvudnyckelmetadata, är korrekt och att kolumnhuvudnyckelsökvägen överensstämmer med det nyckelsökvägsformat som är giltigt för en viss provider. Vi rekommenderar att du konfigurerar nycklarna med hjälp av verktyg som SQL Server Management Studio, som automatiskt genererar giltiga providernamn och nyckelsökvägar när du utfärdar instruktionen CREATE COLUMN MASTER KEY (Transact-SQL). Mer information finns i Konfigurera Always Encrypted med SQL Server Management Studio och Konfigurera Always Encrypted med PowerShell.
- Se till att ditt program kan komma åt nyckeln i nyckelarkivet. Den här processen kan innebära att ge ditt program åtkomst till nyckeln och/eller nyckelarkivet, beroende på nyckelarkivet, eller att utföra andra viktiga lagringsspecifika konfigurationssteg. Om du till exempel vill komma åt ett nyckellager som implementerar CNG eller CAPI (till exempel en maskinvarusäkerhetsmodul) måste du se till att ett bibliotek som implementerar CNG eller CAPI för din butik är installerat på programdatorn. Mer information finns i Skapa och lagra kolumnhuvudnycklar för Always Encrypted.
Använda Azure Key Vault-providern
Azure Key Vault är ett praktiskt alternativ för att lagra och hantera kolumnhuvudnycklar för Always Encrypted (särskilt om dina program finns i Azure). Microsoft .NET Data Provider för SQL Server innehåller inte någon inbyggd kolumnnyckellagringsprovider för Azure Key Vault, men den är tillgänglig som ett NuGet-paket (Microsoft.Data.SqLClient.AlwaysEncrypted.AzureKeyVaultProvider) som du enkelt kan integrera med ditt program. Mer information finns i Always Encrypted – Skydda känsliga data i SQL Database med datakryptering och lagra dina krypteringsnycklar i Azure Key Vault.
| Class | Description | Providernamn (sökning) | Platform |
|---|---|---|---|
| SqlColumnEncryptionAzureKeyVaultProvider-klass | Provider för Azure Key Vault. | AZURE_KEY_VAULT | Windows, Linux, macOS |
.NET-supportbarhet
| Utgåva | Microsoft.Data.SqlClient-version | .NET-plattformar |
|---|---|---|
| 3.0.0 | 3.0.0+ | .NET Framework 4.6.1+, .NET Core 2.1+, .NET Standard 2.0+ |
| 2.0.0 | 1.1.3+ 2.1.0+ |
.NET Framework 4.6.1+, .NET Core 2.1+ .NET Standard 2.0+ |
| 1.2.0 | 1.0.19269.1+ 2.1.0+ |
.NET Framework 4.6+, .NET Core 2.1+ .NET Standard 2.0+ |
| 1.1.0 | 1.0.19269.1+ | .NET Framework 4.6+, .NET Core 2.1+ |
| 1.0.0 | 1.0.19269.1+ | .NET Framework 4.6+, .NET Core 2.1+ |
Från och med v3.0.0Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider har stöd för cachelagring av kolumnkrypteringsnycklar när providern registreras med SQLConnection.RegisterColumnEncryptionKeyStoreProvidersOnConnection eller SqlCommand.RegisterColumnEncryptionKeyStoreProvidersOnCommand API:er.
Från och med v2.0.0 stöder de nya Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider API:erna Azure.Core och Azure.Identity API:erna för att utföra autentisering med Azure Key Vault. En instans av TokenCredential implementeringen kan nu skickas till SqlColumnEncryptionAzureKeyVaultProvider konstruktorer för att initiera Azure Key Vault-providerobjektet.
Anmärkning
Stödjer Microsoft.Data.SqLClient.AlwaysEncrypted.AzureKeyVaultProvider både valv och hanterade HSM:er i Azure Key Vault.
Exempel som demonstrerar kryptering/dekryptering med Azure Key Vault finns i Azure Key Vault som arbetar med Always Encrypted och Azure Key Vault som arbetar med Always Encrypted med säkra enklaver.
Implementera en leverantör för nyckellagring av anpassad kolumnhuvudnyckel
Om du vill lagra kolumnhuvudnycklar i ett nyckelarkiv som inte stöds av en befintlig provider kan du implementera en anpassad provider genom att utöka klassen SqlColumnEncryptionKeyStoreProvider och registrera providern med någon av följande metoder:
- SqlConnection.RegisterColumnEncryptionKeyStoreProviders
- SqlConnection.RegisterColumnEncryptionKeyStoreProvidersOnConnection (tillagd i version 3.0.0)
- SqlCommand.RegisterColumnEncryptionKeyStoreProvidersOnCommand (tillagd i version 3.0.0)
public class MyCustomKeyStoreProvider : SqlColumnEncryptionKeyStoreProvider
{
public const string ProviderName = "MY_CUSTOM_STORE";
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(MyCustomKeyStoreProvider.ProviderName, new MyCustomKeyStoreProvider());
SqlConnection.RegisterColumnEncryptionKeyStoreProviders(providers);
// ...
}
}
Prioritet för kolumnkrypteringsnyckelcache
Det här avsnittet gäller för version 3.0 och senare av Microsoft .NET Data Provider för SQL Server.
Kolumnkrypteringsnycklarna (CEK) som dekrypteras av anpassade nyckellagringsproviders som är registrerade på en anslutning eller kommandoinstans cachelagras inte av Microsoft .NET Data Provider för SQL Server. Leverantörer av anpassade nyckellager bör implementera sin egen CEK-cachelagringsmekanism.
Från och med v3.0.0 av Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProviderhar varje instans av Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider sin egen CEK-cachelagringsimplementering. När de registreras på en anslutning eller kommandoinstans rensas CEK:er som dekrypteras av en instans av Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider när den instansen hamnar utanför omfånget:
class Program
{
private static string connectionString;
static void Main()
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand command = connection.CreateCommand())
{
Dictionary<string, SqlColumnEncryptionKeyStoreProvider> customKeyStoreProviders = new Dictionary<string, SqlColumnEncryptionKeyStoreProvider>();
SqlColumnEncryptionAzureKeyVaultProvider azureKeyVaultProvider = new SqlColumnEncryptionAzureKeyVaultProvider(new DefaultAzureCredential());
customKeyStoreProviders.Add(SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, azureKeyVaultProvider);
command.RegisterColumnEncryptionKeyStoreProvidersOnCommand(customKeyStoreProviders);
// Perform database operation using Azure Key Vault Provider
// Any decrypted column encryption keys will be cached
} // Column encryption key cache of "azureKeyVaultProvider" is cleared when "azureKeyVaultProvider" goes out of scope
}
}
}
Anmärkning
CEK-cachelagring som implementeras av leverantörer av anpassade nyckellager inaktiveras av drivrutinen om nyckellagringsproviderinstansen är registrerad i drivrutinen globalt med hjälp av metoden SqlConnection.RegisterColumnEncryptionKeyStoreProviders . Varje implementering av CEK-cachelagring bör referera till värdet för SqlColumnEncryptionKeyStoreProvider.ColumnEncryptionKeyCacheTtl innan en CEK lagras i cache och inte lagra den i cache om värdet är noll. Detta kommer att undvika duplicerad cachelagring och eventuell användarförvirring när de försöker konfigurera cachelagring av nycklar.
Registrera en leverantör för anpassad kolumnhuvudnyckellagring
Det här avsnittet gäller för version 3.0 och senare av providern.
Anpassade huvudnyckellagringsleverantörer kan registreras med drivrutinen i tre olika lager. Prioriteten för de tre registreringarna är följande:
- Registreringen per kommando kommer att kontrolleras om den inte är tom.
- Om registreringen per kommando är tom kontrolleras registreringen per anslutning om den inte är tom.
- Om registreringen per anslutning är tom kontrolleras den globala registreringen.
När en nyckellagerleverantör hittas på registreringsnivå kommer drivrutinen INTE att använda andra registreringar för att söka efter en leverantör. Om leverantörer är registrerade men korrekt leverantör inte hittas på en viss nivå, genereras ett undantag som endast innehåller de registrerade leverantörerna som kontrollerats i registreringen.
De inbyggda huvudnyckellagringsprovidrar för kolumner som är tillgängliga för Windows Certificate Store, CNG Store och CSP är förregistrerade.
De tre registreringsnivåerna stöder olika scenarier vid frågor mot krypterade data. Lämplig metod kan användas för att säkerställa att en användare av ett program kan komma åt klartextdata om de kan tillhandahålla den nödvändiga kolumnhuvudnyckeln genom att autentisera mot nyckelarkivet som innehåller kolumnhuvudnyckeln.
Program som delar en SqlConnection-instans mellan flera användare kanske vill använda SqlCommand.RegisterColumnEncryptionKeyStoreProvidersOnCommand. Varje användare måste registrera en nyckellagringsprovider på en SqlCommand-instans innan en fråga körs för att få åtkomst till en krypterad kolumn. Om nyckellagringsprovidern kan komma åt den nödvändiga kolumnhuvudnyckeln i nyckelarkivet med hjälp av användarens angivna autentiseringsuppgifter lyckas frågan.
Program som skapar en SqlConnection-instans för varje användare kanske vill använda SqlConnection.RegisterColumnEncryptionKeyStoreProvidersOnConnection. Nyckelförvaringsleverantörer som är registrerade med den här metoden kan användas av anslutningen för alla frågor som har åtkomst till krypterad data.
Nyckellagringsprovidrar som registrerats med hjälp av SqlConnection.RegisterColumnEncryptionKeyStoreProviders använder den identitet som programmet anger när det autentiseras mot nyckelarkivet.
I följande exempel visas företräde för anpassade kolumnhuvudnyckellagerproviders som är registrerade på en anslutningsinstans.
class Program
{
static void Main()
{
Dictionary<string, SqlColumnEncryptionKeyStoreProvider> customKeyStoreProviders = new Dictionary<string, SqlColumnEncryptionKeyStoreProvider>();
MyCustomKeyStoreProvider myProvider = new MyCustomKeyStoreProvider();
customKeyStoreProviders.Add("MY_CUSTOM_STORE", myProvider);
// Registers the provider globally
SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customKeyStoreProviders);
using (SqlConnection connection = new SqlConnection(connectionString))
{
customKeyStoreProviders.Clear();
SqlColumnEncryptionAzureKeyVaultProvider azureKeyVaultProvider = new SqlColumnEncryptionAzureKeyVaultProvider();
customKeyStoreProviders.Add(SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, azureKeyVaultProvider);
// Registers the provider on the connection
// These providers will take precedence over globally registered providers
connection.RegisterColumnEncryptionKeyStoreProvidersOnConnection(customKeyStoreProviders);
}
}
}
I följande exempel visas prioriteten för anpassade huvudnyckellagringsproviders för anpassade kolumner som är registrerade på en kommandoinstans:
class Program
{
static void Main()
{
Dictionary<string, SqlColumnEncryptionKeyStoreProvider> customKeyStoreProviders = new Dictionary<string, SqlColumnEncryptionKeyStoreProvider>();
MyCustomKeyStoreProvider firstProvider = new MyCustomKeyStoreProvider();
customKeyStoreProviders.Add("FIRST_CUSTOM_STORE", firstProvider);
// Registers the provider globally
SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customKeyStoreProviders);
using (SqlConnection connection = new SqlConnection(connectionString))
{
customKeyStoreProviders.Clear();
MyCustomKeyStoreProvider secondProvider = new MyCustomKeyStoreProvider();
customKeyStoreProviders.Add("SECOND_CUSTOM_STORE", secondProvider);
// Registers the provider on the connection
connection.RegisterColumnEncryptionKeyStoreProvidersOnConnection(customKeyStoreProviders);
using (SqlCommand command = connection.CreateCommand())
{
customKeyStoreProviders.Clear();
SqlColumnEncryptionAzureKeyVaultProvider azureKeyVaultProvider = new SqlColumnEncryptionAzureKeyVaultProvider();
customKeyStoreProviders.Add(SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, azureKeyVaultProvider);
// Registers the provider on the command
// These providers will take precedence over connection-level providers and globally registered providers
command.RegisterColumnEncryptionKeyStoreProvidersOnCommand(customKeyStoreProviders);
}
}
}
}
Använda kolumnhuvudnyckellagringsproviders för programmatisk nyckeletablering
När Microsoft .NET Data Provider för SQL Server kommer åt krypterade kolumner söker den transparent efter och anropar den högra kolumnens huvudnyckellagringsprovider för att dekryptera kolumnkrypteringsnycklar. Normalt anropar din normala programkod inte kolumnhuvudnyckellagringsprovidrar direkt. Du kan dock instansiera och anropa en provider explicit för att programmatiskt skapa och hantera Always Encrypted-nycklar: för att generera en krypterad kolumnkrypteringsnyckel och dekryptera en kolumnkrypteringsnyckel (till exempel som huvudnyckelrotation för delkolumner). Mer information finns i Översikt över nyckelhantering för Always Encrypted. Du kan bara implementera dina egna nyckelhanteringsverktyg om du använder en anpassad nyckellagringsprovider. När du använder nycklar som lagras i nyckellager, för vilka inbyggda leverantörer finns, och eller i Azure Key Vault, kan du använda befintliga verktyg, till exempel SQL Server Management Studio eller PowerShell, för att hantera och etablera nycklar. Exemplet nedan visar hur du genererar en kolumnkrypteringsnyckel och använder klassen SqlColumnEncryptionCertificateStoreProvider för att kryptera nyckeln med ett certifikat.
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);
}
Kontrollera prestandapåverkan för Always Encrypted
Eftersom Always Encrypted är en krypteringsteknik på klientsidan observeras de flesta prestandakostnaderna på klientsidan, inte i databasen. Förutom kostnaden för krypterings- och dekrypteringsåtgärder är andra prestandakällor på klientsidan:
- Extra rundresor till databasen för att hämta metadata för frågeparametrar.
- Anropar ett huvudnyckelarkiv för kolumner för att få åtkomst till en kolumnhuvudnyckel.
I det här avsnittet beskrivs de inbyggda prestandaoptimeringarna i Microsoft .NET Data Provider för SQL Server och hur du kan styra effekten av ovanstående två faktorer på prestanda.
Styr rundturer för att hämta metadata för frågeparametrar
Om Always Encrypted är aktiverat för en anslutning anropar Microsoft .NET Data Provider för SQL Serversom standard sys.sp_describe_parameter_encryption för varje parametriserad fråga och skickar frågeutsatsen (utan parametervärden) till SQL Server. sys.sp_describe_parameter_encryption analyserar frågeuttryck för att ta reda på om några parametrar behöver krypteras, och i så fall returnerar den krypteringsrelaterad information som gör det möjligt för Microsoft .NET Data Provider för SQL Server att kryptera parametervärden. Ovanstående beteende säkerställer en hög transparensnivå för klientprogrammet. Programmet (och programutvecklaren) behöver inte vara medvetna om vilka frågor som har åtkomst till krypterade kolumner, så länge värdena för krypterade kolumner skickas till Microsoft .NET Data Provider för SQL Server i SqlParameter-objekt.
Cachelagring av frågemetadata
Microsoft .NET Data Provider för SQL Server cachelagrar resultatet av sys.sp_describe_parameter_encryption för varje frågeuttryck. Så om samma frågeuttryck körs flera gånger anropar drivrutinen bara sys.sp_describe_parameter_encryption en gång. Cachelagring av krypteringsmetadata för frågeinstruktioner minskar avsevärt prestandakostnaden för att hämta metadata från databasen. Cachelagring är aktiverat som standard. Du kan inaktivera cachelagring av parametermetadata genom att ange egenskapen SqlConnection.ColumnEncryptionQueryMetadataCacheEnabled till false, men det rekommenderas inte förutom i sällsynta fall som den som beskrivs nedan:
Överväg en databas som har två olika scheman: s1 och s2. Varje schema innehåller en tabell med samma namn: t. Definitionerna för tabellerna s1.t och s2.t är identiska, förutom krypteringsrelaterade egenskaper: En kolumn med namnet c, i s1.t krypteras inte och krypteras i s2.t. Databasen har två användare: u1 och u2. Standardschemat för u1 användarna är s1. Standardschemat för u2 är s2. Ett .NET-program öppnar två anslutningar till databasen, personifierar u1 användaren på en anslutning och u2 användaren på en annan anslutning. Programmet skickar en fråga med en parameter som riktar sig mot c kolumnen över anslutningen för användaren u1 (frågan anger inte schemat, så standardanvändarschemat antas). Därefter skickar programmet samma fråga över anslutningen för u2 användaren. Om cachelagring av frågemetadata är aktiverat fylls cacheminnet efter den första frågan med metadata som anger c att kolumnen, som frågeparametern riktar sig mot, inte är krypterad. Eftersom den andra frågan har samma frågeuttryck används informationen som lagras i cacheminnet. Därför skickar drivrutinen frågan utan att kryptera parametern (vilket är felaktigt, eftersom målkolumnen, s2.t.c, är krypterad), vilket läcker parameterns klartextvärde till servern. Servern identifierar den inkompatibiliteten och tvingar drivrutinen att uppdatera cachen, så programmet skickar frågan transparent igen med det korrekt krypterade parametervärdet. I sådana fall bör cachelagring inaktiveras för att förhindra läckage av känsliga värden till servern.
Ange Always Encrypted på frågenivå
Om du vill kontrollera prestandapåverkan vid hämtning av krypteringsmetadata för parametriserade frågor kan du aktivera Always Encrypted för enskilda frågor i stället för att konfigurera den för anslutningen. På så sätt kan du se till att sys.sp_describe_parameter_encryption endast anropas för frågor som du vet har parametrar som riktar sig till krypterade kolumner. Observera dock att genom att göra det minskar du transparensen för kryptering: om du ändrar krypteringsegenskaperna för dina databaskolumner kan du behöva ändra koden för ditt program för att justera det med schemaändringarna.
Anmärkning
Om du anger Always Encrypted på frågenivå begränsas prestandafördelarna med cachelagring av parameterkrypteringsmetadata.
För att styra Always Encrypted-beteendet för enskilda frågor måste du använda den här konstruktorn för SqlCommand och SqlCommandColumnEncryptionSetting. Här följer några användbara riktlinjer:
- Om ett klientprogram i de flesta fall kör frågor som har åtkomst till krypterade kolumner:
- Ange nyckelordet Kolumnkrypteringsinställning för anslutningssträng till Aktiverad.
- Ange SqlCommandColumnEncryptionSetting till Inaktiverad för enskilda frågor som inte har åtkomst till några krypterade kolumner. Den här inställningen inaktiverar både anropande sys.sp_describe_parameter_encryption och ett försök att dekryptera alla värden i resultatuppsättningen.
- Ange SqlCommandColumnEncryptionSetting till ResultSetOnly för enskilda frågor som inte har några parametrar som kräver kryptering, men hämtar data från krypterade kolumner. Den här inställningen inaktiverar anrop av sys.sp_describe_parameter_encryption och parameterkryptering. Frågan kommer att kunna dekryptera resultatet från krypteringskolumner.
- Om de flesta frågor som ett klientprogram kör inte har åtkomst till krypterade kolumner:
- Ange nyckelordet Kolumnkrypteringsinställning i den anslutningssträngen till Inaktiverad.
- Ange SqlCommandColumnEncryptionSetting till Aktiverad för enskilda frågor som har parametrar som behöver krypteras. Den här inställningen aktiverar både anropande sys.sp_describe_parameter_encryption och dekryptering av eventuella frågeresultat som hämtats från krypterade kolumner.
- Ange SqlCommandColumnEncryptionSetting till ResultSetOnly för frågor som inte har några parametrar som kräver kryptering, men hämta data från krypterade kolumner. Den här inställningen inaktiverar anrop av sys.sp_describe_parameter_encryption och parameterkryptering. Frågan kommer att kunna dekryptera resultatet från krypteringskolumner.
I exemplet nedan är Always Encrypted inaktiverat för databasanslutningen. Frågan som programmet utfärdar har en parameter som riktar sig mot kolumnen LastName som inte är krypterad. Frågan hämtar data från kolumnerna SSN och BirthDate som båda är krypterade. I sådana fall krävs det inte att du anropar sys.sp_describe_parameter_encryption för att hämta krypteringsmetadata. Dekrypteringen av frågeresultatet måste dock aktiveras, så att programmet kan ta emot klartextvärden från de två krypterade kolumnerna. Inställningen SqlCommandColumnEncryptionSettingResultSetOnly används för att säkerställa detta.
string connectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true";
using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand(@"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE [LastName]=@LastName",
connection, null, SqlCommandColumnEncryptionSetting.ResultSetOnly))
{
connection.Open();
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());
}
}
}
}
Cachelagring av kolumnkrypteringsnyckel
För att minska antalet anrop till kolumnhuvudnyckellagringen för att dekryptera kolumnkrypteringsnycklar, cachelagrar Microsoft .NET Data Provider för SQL Server kolumnkrypteringsnycklarna i klartext i minnet. När providern har fått krypteringsnyckelvärdet för krypterad kolumn från databasmetadata försöker drivrutinen först hitta krypteringsnyckeln för oformaterad kolumn som motsvarar det krypterade nyckelvärdet. Drivrutinen anropar nyckelarkivet som endast innehåller kolumnhuvudnyckeln om den inte kan hitta krypteringsnyckelvärdet för krypterad kolumn i cacheminnet.
Cacheposterna avlägsnas efter ett konfigurerbart time to live-intervall av säkerhetsskäl. Standardvärdet för time to live är 2 timmar. Om du har strängare säkerhetskrav för hur länge kolumnkrypteringsnycklar kan cachelagras i klartext i programmet kan du ändra det med egenskapen SqlConnection.ColumnEncryptionKeyCacheTtl.
Anpassade nyckelarkivprovidrar som registrerats med SqlConnection.RegisterColumnEncryptionKeyStoreProvidersOnConnection och SqlCommand.RegisterColumnEncryptionKeyStoreProvidersOnCommand får inte sina dekrypterade kolumn-krypteringsnycklar cachelagrade av Microsoft .NET Data Provider för SQL Server. I stället måste leverantörer av anpassade nyckellager implementera sin egen cachelagringsmekanism.
Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider
v3.0.0 och senare levereras med en egen cachelagringsimplementering.
För att stödja scenarier där olika användare av samma program kan köra flera frågor kan anpassade nyckellagringsleverantörer mappas till en användare och registreras på en anslutning eller kommandoinstans som är specifik för användaren. I följande exempel visas hur en instans av Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider kan återanvändas mellan olika SqlCommand objekt för samma användare. Dess kolumnkrypteringsnyckelcache kommer att kvarstå över flera förfrågningar, vilket minskar antalet resor till nyckellagret.
using Microsoft.Data.SqlClient;
using Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider;
using System.Collections.Generic;
class Program
{
// Maps a SqlColumnEncryptionAzureKeyVaultProvider to some object that represents a user
static Dictionary<object, SqlColumnEncryptionAzureKeyVaultProvider> providerByUser = new();
void ExecuteSelectQuery(object user, SqlConnection connection)
{
// Check if the user already has a SqlColumnEncryptionAzureKeyVaultProvider
SqlColumnEncryptionAzureKeyVaultProvider azureKeyVaultProvider = providerByUser[user];
if (azureKeyVaultProvider is null)
{
// Create a new SqlColumnEncryptionAzureKeyVaultProvider with the user's credentials and save it for future use
azureKeyVaultProvider = new SqlColumnEncryptionAzureKeyVaultProvider();
providerByUser[user] = azureKeyVaultProvider;
}
Dictionary<string, SqlColumnEncryptionKeyStoreProvider> customProviders = new();
customProviders.Add(SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, azureKeyVaultProvider);
using SqlCommand command = new("SELECT * FROM Customers", connection);
command.RegisterColumnEncryptionKeyStoreProvidersOnCommand(customProviders);
// Perform database operations
// Any decrypted column encryption keys will be cached by azureKeyVaultProvider
}
void ExecuteUpdateQuery(object user, SqlConnection connection)
{
// Check if the user already has a SqlColumnEncryptionAzureKeyVaultProvider
SqlColumnEncryptionAzureKeyVaultProvider azureKeyVaultProvider = providerByUser[user];
if (azureKeyVaultProvider is null)
{
// Create a new SqlColumnEncryptionAzureKeyVaultProvider with the user's credentials and save it for future use
azureKeyVaultProvider = new SqlColumnEncryptionAzureKeyVaultProvider();
providerByUser[user] = azureKeyVaultProvider;
}
Dictionary<string, SqlColumnEncryptionKeyStoreProvider> customProviders = new();
customProviders.Add(SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, azureKeyVaultProvider);
using SqlCommand command = new("UPDATE Customers SET Name = 'NewName' WHERE CustomerId = 1", connection);
command.RegisterColumnEncryptionKeyStoreProvidersOnCommand(customProviders);
// Perform database operations
// Any decrypted column encryption keys will be cached by azureKeyVaultProvider
}
}
Aktivera extra skydd för en komprometterad SQL Server
Som standard förlitar sig Microsoft .NET Data Provider för SQL Server på databassystemet (SQL Server eller Azure SQL Database) för att tillhandahålla metadata om vilka kolumner i databasen som krypteras och hur. Med krypteringsmetadata kan Microsoft .NET Data Provider för SQL Server kryptera frågeparametrar och dekryptera frågeresultat utan indata från programmet, vilket avsevärt minskar antalet ändringar som krävs i programmet. Men om SQL Server-processen komprometteras och en angripare manipulerar metadata som SQL Server skickar till Microsoft .NET Data Provider för SQL Server kan angriparen stjäla känslig information. I det här avsnittet beskrivs API:er som hjälper till att ge en extra skyddsnivå mot den här typen av angrepp, till priset av minskad transparens.
Tvinga parameterkryptering
Innan Microsoft .NET Data Provider för SQL Server skickar en parametriserad fråga till SQL Server ber den SQL Server (genom att anropa sys.sp_describe_parameter_encryption) att analysera frågeutsatsen och ange information om vilka parametrar i frågan som ska krypteras. En komprometterad SQL Server-instans kan vilseleda Microsoft .NET Data Provider för SQL Server genom att skicka metadata som anger att parametern inte riktar sig mot en krypterad kolumn, även om kolumnen är krypterad i databasen. Därför krypterar inte Microsoft .NET Data Provider för SQL Server parametervärdet och skickar det som klartext till den komprometterade SQL Server-instansen.
För att förhindra en sådan attack kan ett program ange egenskapen SqlParameter.ForceColumnEncryption för parametern till true. Den här inställningen gör att Microsoft .NET Data Provider för SQL Server genererar ett undantag, om metadata som den har tagit emot från servern anger att parametern inte behöver krypteras.
Även om användningen av egenskapen SqlParameter.ForceColumnEncryption hjälper till att förbättra säkerheten, minskar det också transparensen för kryptering till klientprogrammet. Om du uppdaterar databasschemat för att ändra uppsättningen krypterade kolumner kan du också behöva göra programändringar.
Följande kodexempel visar hur du använder egenskapen SqlParameter.ForceColumnEncryption för att förhindra att personnummer skickas i klartext till databasen.
using (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);
using (SqlDataReader reader = cmd.ExecuteReader())
{
// Do something.
}
}
Konfigurera huvudnyckelsökvägar för betrodda kolumner
SQL Server-krypteringsmetadata returneras för frågeparametrar som riktar sig mot krypterade kolumner och för de resultat som hämtas från krypteringskolumner ingår nyckelsökvägen för kolumnhuvudnyckeln som identifierar nyckelarkivet och platsen för nyckeln i nyckelarkivet. Om SQL Server-instansen komprometteras kan den skicka nyckelsökvägen som dirigerar Microsoft .NET Data Provider för SQL Server till den plats som kontrolleras av en angripare. Den här processen kan leda till läckande autentiseringsuppgifter för nyckelarkivet om nyckelarkivet kräver att programmet autentiseras.
För att förhindra sådana attacker kan programmet ange listan över betrodda nyckelsökvägar för en viss server med hjälp av egenskapen SqlConnection.ColumnEncryptionTrustedMasterKeyPaths. Om Microsoft .NET Data Provider för SQL Server tar emot en nyckelsökväg utanför listan över betrodda nyckelsökvägar utlöser den ett undantag.
Även om inställningen av betrodda nyckelsökvägar förbättrar säkerheten för ditt program, måste du ändra koden eller/och konfigurationen av programmet när du roterar kolumnhuvudnyckeln (när kolumnhuvudnyckelns sökväg ändras).
I följande exempel visas hur du konfigurerar huvudnyckelsökvägar för betrodda kolumner:
// 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);
Kopiera krypterade data med hjälp av SqlBulkCopy
Med SqlBulkCopy kan du kopiera data, som redan är krypterade och lagrade i en tabell, till en annan tabell, utan att dekryptera data. Så här gör du:
- Kontrollera att krypteringskonfigurationen för måltabellen är identisk med konfigurationen av källtabellen. I synnerhet måste båda tabellerna ha samma kolumner krypterade och kolumnerna måste krypteras med samma krypteringstyper och samma krypteringsnycklar. Om någon av målkolumnerna krypteras på ett annat sätt än motsvarande källkolumn kan du inte dekryptera data i måltabellen efter kopieringsåtgärden. Data kommer att skadas.
- Konfigurera båda databasanslutningarna till källtabellen och till måltabellen utan Always Encrypted aktiverat.
- Ange alternativet
AllowEncryptedValueModifications(se SqlBulkCopyOptions).
Anmärkning
Var försiktig när du anger AllowEncryptedValueModifications. Den här inställningen kan leda till att databasen skadas eftersom Microsoft .NET Data Provider för SQL Server inte kontrollerar om data verkligen är krypterade eller om de är korrekt krypterade med samma krypteringstyp, algoritm och nyckel som målkolumnen.
Här är ett exempel som kopierar data från en tabell till en annan. Kolumnerna SSN och BirthDate antas vara krypterade.
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())
using (SqlBulkCopy copy = new SqlBulkCopy(targetConnectionString, SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.AllowEncryptedValueModifications))
{
copy.EnableStreaming = true;
copy.DestinationTableName = targetTable;
copy.WriteToServer(reader);
}
}
}
}
Always Encrypted API-referensen
Namnområde:Microsoft.Data.SqlClient
Sammansättning: Microsoft.Data.SqlClient.dll
| Namn | Description |
|---|---|
| SqlColumnEncryptionCertificateStoreProvider-klass | En leverantör av nyckellagring för Windows Certificate Store. |
| SqlColumnEncryptionCngProvider-klass | En nyckellagerleverantör för Microsoft Cryptography API: Next Generation (CNG). |
| SqlColumnEncryptionCspProvider-klass | En nyckellagerleverantör för Microsoft CAPI-baserade kryptografiska tjänstleverantörer (CSP). |
| SqlColumnEncryptionKeyStoreProvider-klass | Basklass för nyckellagringsleverantörer. |
| SqlCommandColumnEncryptionSetting Enumeration | Inställningar för att styra beteendet för Always Encrypted för enskilda frågor. |
| Uppräkning för SqlConnectionAttestationProtocol | Anger ett värde för attesteringsprotokollet när always encrypted används med säkra enklaver |
| SqlConnectionColumnEncryptionSetting Enumeration | Inställningar för att aktivera kryptering och dekryptering för en databasanslutning. |
| SqlConnectionStringBuilder.Kolumnkrypteringsinställningsegenskap | Hämtar och anger Always Encrypted i anslutningssträngen. |
| SqlConnection.ColumnEncryptionQueryMetadataCacheEnabled-egenskapen | Aktiverar och inaktiverar cachelagring av metadata för krypteringsfråga. |
| SqlConnection.ColumnEncryptionKeyCacheTtl-egenskap | Hämtar och anger livstid för poster i kolumnkrypteringsnyckelns cacheminne. |
| SqlConnection.ColumnEncryptionTrustedMasterKeyPaths-egenskapen | Gör att du kan ange en lista över betrodda nyckelsökvägar för en databasserver. Om drivrutinen under bearbetningen av en programfråga tar emot en nyckelsökväg som inte finns med i listan misslyckas frågan. Den här egenskapen ger extra skydd mot säkerhetsattacker som omfattar en komprometterad SQL Server som tillhandahåller falska nyckelsökvägar, vilket kan leda till läckande autentiseringsuppgifter för nyckelarkivet. |
| SqlConnection.RegisterColumnEncryptionKeyStoreProviders Method | Gör att du kan registrera anpassade nyckellagringsleverantörer. Det är ett uppslagsverk som mappar nyckellagringsleverantörsnamn till nyckellagringsleverantörsimplementationer. |
| SqlCommand-konstruktor (String, SqlConnection, SqlTransaction, SqlCommandColumnEncryptionSetting) | Gör att du kan styra beteendet för Always Encrypted för enskilda frågor. |
| SqlParameter.ForceColumnEncryptionProperty | Framtvingar kryptering av en parameter. Om SQL Server informerar drivrutinen om att parametern inte behöver krypteras misslyckas frågan med parametern . Den här egenskapen ger extra skydd mot säkerhetsattacker som innebär att en komprometterad SQL Server tillhandahåller felaktiga krypteringsmetadata till klienten, vilket kan leda till att data avslöjas. |
nyckelord för anslutningssträng : Column Encryption Setting=enabled |
Aktiverar eller inaktiverar Always Encrypted-funktioner för anslutningen. |
Se även
- Alltid krypterad
- Always Encrypted med säkra enklaver
- SQL Database-självstudie: Skydda känsliga data med Always Encrypted
- Självstudie: Utveckla ett .NET-program med Always Encrypted med säkra enklaver
- Exempel: Azure Key Vault fungerar med Always Encrypted
- Exempel: Azure Key Vault arbetar med Always Encrypted med säkra enklaver