Megosztás:


Az Always Encrypted használata az SQL Serverhez készült Microsoft .NET-adatszolgáltatóval

A következőre vonatkozik: .NET Framework .NET .NET Standard

Ez a cikk tájékoztatást ad arról, hogyan fejleszthet .NET alkalmazásokat az Always Encrypted vagy az Always Encrypted biztonságos enklávékkal segítségével, valamint az Microsoft .NET Data Provider for SQL Server használatával.

Az Always Encrypted lehetővé teszi az ügyfélalkalmazások számára a bizalmas adatok titkosítását, és soha nem fedik fel az ADATOKAT vagy a titkosítási kulcsokat az SQL Server vagy az Azure SQL Database számára. Az Always Encrypted-kompatibilis illesztőprogramok, például az SQL Server Microsoft .NET-adatszolgáltatója, ezt a biztonságot úgy érik el, hogy transzparensen titkosítják és visszafejtik a bizalmas adatokat az ügyfélalkalmazásban. Az illesztő automatikusan meghatározza, hogy mely lekérdezési paraméterek felelnek meg a bizalmas adatbázisoszlopoknak (Always Encrypted használatával védett), és titkosítja ezeknek a paramétereknek az értékeit, mielőtt továbbítanák az adatokat a kiszolgálónak. Hasonlóképpen, az illesztőprogram transzparensen visszafejti a titkosított adatbázis oszlopaiból lekért adatokat a lekérdezési eredményekben. További információ: Alkalmazások fejlesztése Always Encrypted használatával és Alkalmazások fejlesztése Always Encrypted és biztonságos enklávék használatával.

Előfeltételek

  • Konfigurálja az Always Encryptedt az adatbázisban. Ez a folyamat magában foglalja az Always Encrypted kulcsok kiépítését és a kijelölt adatbázisoszlopok titkosításának beállítását. Ha még nem rendelkezik Always Encrypteddel konfigurált adatbázissal, kövesse az oktatóanyag útmutatását : Az Always Encrypted használatának első lépései.
  • Ha az Always Encryptedt biztonságos enklávékkal használja, további előfeltételekért tekintse meg az Always Encrypted és biztonságos enklávék használatával végzett alkalmazások fejlesztése című témakört.
  • Győződjön meg arról, hogy a szükséges .NET-platform telepítve van a fejlesztői gépen. A Microsoft.Data.SqlClient használatával az Always Encrypted funkció a .NET-keretrendszerhez és a .NET Core-hoz is támogatott. Győződjön meg arról, hogy a .NET-keretrendszer 4.6-os vagy újabb, illetve a .NET Core 2.1-es vagy újabb verziója a fejlesztési környezet cél .NET-platformverziójaként van konfigurálva. A Microsoft.Data.SqlClient 2.1.0-s és újabb verziójával az Always Encrypted funkció a .NET Standard 2.0-s verziójában is támogatott. Az Always Encrypted biztonságos enklávékkal való használatához a .NET Standard 2.1 szükséges. Ha igazolás nélkül szeretné használni a VBS-enklávékat, a Microsoft.Data.SqlClient 4.1-es vagy újabb verziójára van szükség. Ha Visual Studiót használ, tekintse meg a keretrendszer célzási áttekintését.

Az alábbi táblázat összefoglalja az Always Encrypted és a Microsoft.Data.SqlClient használatához szükséges .NET-platformokat.

Always Encrypted támogatása Az "Always Encrypted" támogatása biztonságos enklávéval Cél-keretrendszer Microsoft.Data.SqlClient-verzió Operációs rendszer
Igen Igen .NET-keretrendszer 4.6+ 1.1.0+ Windows
Igen Igen .NET Core 2.1+ 2.1.0+1 Windows, Linux, macOS
Igen Nem .NET Standard 2.0 2.1.0+ Windows, Linux, macOS
Igen Igen .NET Standard 2.1+ 2.1.0+ Windows, Linux, macOS

Megjegyzés:

1 A Microsoft.Data.SqlClient 2.1.0-s verziója előtt az Always Encrypted csak Windows rendszeren támogatott.

Az Always Encrypted engedélyezése alkalmazás-lekérdezésekhez

A paraméterek titkosításának és a titkosított oszlopokra irányuló lekérdezési eredmények visszafejtésének engedélyezésének legegyszerűbb módja a kapcsolati sztring kulcsszó értékének Column Encryption Settingengedélyezése.

Az alábbi példa egy kapcsolati sztringet használ, amely engedélyezi az Always Encryptedt:

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

A következő kódrészlet egyenértékű példa az SqlConnectionStringBuilder.ColumnEncryptionSetting tulajdonság használatával.

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

Az Always Encrypted egyéni lekérdezésekhez is engedélyezhető. Tekintse meg az Always Encrypted(Mindig titkosított) szakasz teljesítményhatásának szabályozását alább. Az Always Encrypted engedélyezése nem elegendő a titkosítás vagy a visszafejtés sikerességéhez. A következőket is ellenőriznie kell:

  • Az alkalmazás rendelkezik a VIEW ANY COLUMN MASTER KEY DEFINITION és VIEW ANY COLUMN ENCRYPTION KEY DEFINITION adatbázis engedélyekkel, amely az adatbázisban lévő Always Encrypted kulcsok metaadatainak eléréséhez szükséges. További részletekért tekintse meg az Always Encrypted (Adatbázismotor) Adatbázis-engedélyek szakaszát.
  • Az alkalmazás hozzáférhet az oszlop főkulcshoz, amely védi az oszloptitkosítási kulcsokat, és ezek titkosítják a lekérdezett adatbázisoszlopokat.

Az Always Encrypted engedélyezése biztonságos enklávékkal

A Microsoft.Data.SqlClient 1.1.0-s verziójától kezdve az illesztőprogram biztonságos enklávékkal támogatja az Always Encryptedt.

Az alkalmazások enklávékkal történő fejlesztésével kapcsolatos általános információkért lásd: Alkalmazások fejlesztése az Always Encrypted használatával biztonságos enklávékkal.

Az adatbázis-kapcsolatok enklávészámításának engedélyezéséhez az Always Encrypted engedélyezése mellett a következő kapcsolati sztring-kulcsszavakat kell megadnia (az előző szakaszban leírtak szerint):

  • Attestation Protocol - egy igazolási protokollt határoz meg.

    • Ha ez a kulcsszó nincs megadva, a biztonságos enklávék le lesznek tiltva a kapcsolaton.
    • Ha az SQL Servert virtualizációalapú biztonsági (VBS) enklávékkal és Gazdagépőr szolgáltatással (HGS) használja, ennek a kulcsszónak az értéke legyen HGS.
    • Ha Az Azure SQL Database-t Intel SGX-enklávékkal és Microsoft Azure-igazolással használja, ennek a kulcsszónak az értéke legyen AAS.
    • Ha az Azure SQL Database-et vagy az SQL Servert VBS-enklávékkal használja, és el szeretné kerülni az igazolást, ennek a kulcsszónak az értéke legyen None. A 4.1-es vagy újabb verziót igényli.

    Megjegyzés:

    A "Nincs" (nincs igazolás) az egyetlen lehetőség, amely jelenleg támogatott az Azure SQL Database-ben található VBS-enklávék esetében.

  • Enclave Attestation URL - egy igazolási URL-címet (egy igazolási szolgáltatás végpontját) határoz meg. Be kell szereznie a környezet igazolási URL-címét az igazolási szolgáltatás rendszergazdájától.

Részletes oktatóanyagért tekintse meg az oktatóanyagot: .NET-alkalmazás fejlesztése az Always Encrypted használatával biztonságos enklávékkal.

Adatok beolvasása és módosítása titkosított oszlopokban

Miután engedélyezte az Always Encryptedt az alkalmazáslekérdezésekhez, használhatja a szabványos SqlClient API-kat (lásd: Adatok lekérése és módosítása az ADO.NET-ben) vagy a Microsoft.Data.SqlClient névtérben definiált SQL Server API-k Microsoft .NET-adatszolgáltatója segítségével titkosított adatbázisoszlopokban lévő adatok lekéréséhez vagy módosításához. Ha az alkalmazás rendelkezik a szükséges adatbázis-engedélyekkel, és hozzáfér az oszlop főkulcsához, az SQL Server Microsoft .NET-adatszolgáltatója titkosítja a titkosított oszlopokat megcélzó lekérdezési paramétereket, és visszafejti a titkosított oszlopokból lekért adatokat, és visszaadja az adatbázisséma oszlopaihoz beállított SQL Server-adattípusoknak megfelelő .NET-típusok egyszerű szöveges értékeit. Ha az Always Encrypted nincs engedélyezve, a titkosított oszlopokat megcélzott paraméterekkel rendelkező lekérdezések sikertelenek lesznek. A lekérdezések továbbra is lekérhetik az adatokat a titkosított oszlopokból, amíg a lekérdezés nem tartalmaz titkosított oszlopokat célzó paramétereket. Az SQL Server Microsoft .NET-adatszolgáltatója azonban nem kísérli meg visszafejteni a titkosított oszlopokból lekért értékeket, és az alkalmazás binárisan titkosított adatokat (bájttömbökként) fog kapni.

Az alábbi táblázat a lekérdezések viselkedését foglalja össze attól függően, hogy az Always Encrypted engedélyezve van-e, vagy sem:

Lekérdezési jellemző Az Always Encrypted engedélyezve van, és az alkalmazás hozzáférhet a kulcsokhoz és a kulcs metaadataihoz Az Always Encrypted engedélyezve van, és az alkalmazás nem tudja elérni a kulcsokat vagy a kulcs metaadatait Az "Always Encrypted" funkció le van tiltva.
Titkosított oszlopokat célzó paraméterekkel rendelkező lekérdezések. A paraméterértékek transzparensen titkosítva vannak. Error Error
Titkosított oszlopokból adatokat lekérdező lekérdezések a titkosított oszlopokat célzó paraméterek nélkül. A titkosított oszlopok eredményei transzparensen visszafejthetők. Az alkalmazás megkapja a titkosított oszlopokhoz konfigurált SQL Server-típusoknak megfelelő .NET-adattípusok egyszerű szöveges értékeit. Error A titkosított oszlopok eredményei nem lesznek visszafejtve. Az alkalmazás bájttömbökként (bájt[]) fogadja a titkosított értékeket.

Az alábbi példák az adatok titkosított oszlopokban való beolvasását és módosítását szemléltetik. A példák a céltáblát feltételezik az alábbi sémával. A SSN és a BirthDate oszlop titkosítva van.

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

Adatbeszúrási példa

Ez a példa beszúr egy sort a Betegek táblába. Jegyezze fel a következő részleteket:

  • A mintakód nem tartalmaz titkosítást. A Microsoft .NET-adatszolgáltató az SQL Serverhez automatikusan észleli és titkosítja a titkosított oszlopokat megcélzó paramSSN és paramBirthdate paramétereket. Ez a viselkedés transzparenssé teszi a titkosítást az alkalmazás számára.
  • Az adatbázisoszlopokba beszúrt értékek, beleértve a titkosított oszlopokat, SqlParameter-objektumokként lesznek átadva. Az SqlParameter használata nem kötelező, ha nem titkosított oszlopokba küld értékeket (bár erősen ajánlott, mert segít megelőzni az SQL-injektálást), a titkosított oszlopokat megcélzó értékekhez szükséges. Ha az oszlopokba SSNBirthDate beszúrt értékek a lekérdezési utasításba beágyazott literálként lettek átadva, a lekérdezés meghiúsulna, mert az SQL Server Microsoft .NET-adatszolgáltatója nem tudná meghatározni a célként megadott titkosított oszlopok értékeit, így nem titkosítaná az értékeket. Ennek eredményeképpen a kiszolgáló elutasítja őket, mivel nem kompatibilisek a titkosított oszlopokkal.
  • Az oszlopot megcélzó SSN paraméter adattípusa ANSI (nem Unicode) sztringre van állítva, amely a char/varchar SQL Server-adattípusra van leképezve. Ha a paraméter típusa Unicode karaktersorozatra (String) lett állítva, amely leképeződik az nchar/nvarchar típusra, a lekérdezés sikertelen lesz, mivel az Always Encrypted nem támogatja a titkosított nchar/nvarchar értékek titkosított char/varchar értékekké való átalakítását. Az adattípus-leképezésekkel kapcsolatos információkért tekintse meg az SQL Server adattípus-leképezéseit.
  • Az oszlopba BirthDate beszúrt paraméter adattípusa explicit módon a cél SQL Server-adattípusra van beállítva az SqlParameter.SqlDbType tulajdonság használatával, ahelyett, hogy az SqlParameter.DbType tulajdonság használatakor alkalmazott .NET-típusok implicit leképezésére támaszkodik. Alapértelmezés szerint a DateTime Struktúra a datetime SQL Server adattípusra van leképezve. Mivel az oszlop adattípusa dátum, és az BirthDate Always Encrypted nem támogatja a titkosított dátum/idő értékek titkosított dátumértékekké való konvertálását, az alapértelmezett leképezés használata hibát eredményez.
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();
}

Egyszerű szöveges adatok beolvasása – példa

Az alábbi példa bemutatja az adatok titkosított értékeken alapuló szűrését és egyszerű szöveges adatok titkosított oszlopokból való lekérését.

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());
            }
        }
    }
}

Megjegyzés:

  • Az oszlopra való szűréshez használt WHERE záradékban használt értéket az SSN SqlParameter használatával kell átadni, hogy az SQL Server Microsoft .NET-adatszolgáltatója transzparensen titkosíthassa azt, mielőtt elküldené az adatbázisba.

  • A program által kinyomtatott összes érték szöveges formátumú lesz, mivel a Microsoft .NET-adatszolgáltató SQL Serverhez transzparensen visszafejti a SSN és BirthDate oszlopokból beolvasott adatokat.

  • A lekérdezések akkor végezhetnek egyenlőség-összehasonlítást az oszlopokon, ha determinisztikus titkosítással vannak titkosítva.

Példa titkosított adatok beolvasására

Ha az Always Encrypted nincs engedélyezve, a lekérdezések továbbra is lekérhetik az adatokat titkosított oszlopokból, feltéve, hogy a lekérdezés nem tartalmaz titkosított oszlopokat célzó paramétereket.

Az alábbi példa bemutatja, hogyan lehet bináris titkosított adatokat lekérni a titkosított oszlopokból.

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]));
            }
        }
    }
}

Megjegyzés:

  • Mivel az Always Encrypted nincs engedélyezve a kapcsolati sztringben, a lekérdezés bájttömbök titkosított értékeit SSNBirthDate adja vissza (a program sztringekké alakítja az értékeket).

  • Az Always Encrypted letiltott titkosított oszlopaiból adatokat lekérő lekérdezésnek lehetnek paraméterei, feltéve, hogy egyik paraméter sem céloz meg titkosított oszlopot. A fenti lekérdezés a LastName szerint szűr, amely nincs titkosítva az adatbázisban. Ha a lekérdezést SSN vagy BirthDate alapján szűrjük, a lekérdezés sikertelen lesz.

A titkosított oszlopok lekérdezésével kapcsolatos gyakori problémák elkerülése

Ez a szakasz a .NET-alkalmazásokból származó titkosított oszlopok lekérdezésekor előforduló gyakori hibakategóriákat ismerteti, valamint néhány útmutatást az elkerülésükhöz.

Nem támogatott adattípus-konverziós hibák

Az Always Encrypted kevés konverziót támogat a titkosított adattípusokhoz. A támogatott típuskonverziók részletes listáját az Always Encryptedben találja. Az adattípusok konvertálási hibáinak elkerülése érdekében tegye a következőket:

  • Állítsa be a titkosított oszlopokat célzó paraméterek típusait, hogy a paraméter SQL Server-adattípusa pontosan megegyezik a céloszlop típusával, vagy a paraméter SQL Server-adattípusának konvertálása az oszlop céltípusára támogatott. Az SqlParameter.SqlDbType tulajdonság használatával kényszerítheti a .NET-adattípusok kívánt leképezését adott SQL Server-adattípusokra.
  • Ellenőrizze, hogy a decimális és numerikus SQL Server-adattípusok oszlopait megcélzó paraméterek pontossága és mérete megegyezik-e a céloszlophoz konfigurált pontossági és méretezési értékekkel.
  • Ellenőrizze, hogy a datetime2, datetimeoffset vagy time SQL Server-adattípusok oszlopait megcélzó paraméterek pontossága nem nagyobb-e a céloszlop pontosságánál (a céloszlop értékeit módosító lekérdezésekben).

A titkosított értékek helyett egyszerű szöveg átadása miatti hibák

Minden olyan értéket, amely egy titkosított oszlopot céloz meg, titkosítva kell lennie az alkalmazásban. Egy titkosított oszlop egyszerű szöveges értéke alapján történő beszúrási/módosítási vagy szűrési kísérlet az alábbihoz hasonló hibát eredményez:

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'

Az ilyen hibák megelőzése érdekében győződjön meg arról, hogy:

  • Az Always Encrypted engedélyezve van a titkosított oszlopokat célzó alkalmazás-lekérdezésekhez (a kapcsolati sztringhez vagy egy adott lekérdezés SqlCommand objektumához).
  • Az SqlParameter használatával titkosított oszlopokat célzó adatokat küldhet. Az alábbi példa egy olyan lekérdezést mutat be, amely helytelenül szűr egy konstans/állandó által egy titkosított oszlopon (SSN) ahelyett, hogy a literálist egy SqlParameter-objektumon belül adja át.
using (SqlCommand cmd = connection.CreateCommand())
{
    cmd.CommandText = @"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE SSN = '795-73-9838'";
    cmd.ExecuteNonQuery();
}

Az oszlop főkulcs-tárolóinak használata

Egy paraméterérték titkosításához vagy az adatok lekérdezési eredményekben való visszafejtéséhez az SQL Server Microsoft .NET-adatszolgáltatójának be kell szereznie egy, a céloszlophoz konfigurált oszloptitkosítási kulcsot. Az oszloptitkosítási kulcsok titkosított formában vannak tárolva az adatbázis metaadataiban. Minden oszloptitkosítási kulcshoz tartozik egy oszlopmester kulcs, amelyet az oszloptitkosítási kulcs titkosításához használtak. Az adatbázis metaadatai nem tárolják az oszlop főkulcsait – csak egy adott oszlop főkulcsát és a kulcs helyét tartalmazó kulcstároló adatait tartalmazza.

Egy oszloptitkosítási kulcs egyszerű szöveges értékének lekéréséhez az SQL Server Microsoft .NET-adatszolgáltatója először az oszloptitkosítási kulcsra és annak megfelelő oszlop-főkulcsra vonatkozó metaadatokat szerzi be. Ezután a metaadatokban szereplő információk alapján kapcsolatba lép az oszlop főkulcsát tartalmazó kulcstárolóval, és visszafejti a titkosított oszloptitkosítási kulcsot. Az SQL Server számára készült Microsoft .NET-adatszolgáltató egy oszlop főkulcstároló szolgáltatóval kommunikál, amely az SqlColumnEncryptionKeyStoreProvider osztályból származtatott osztály egy példánya.

Az oszloptitkosítási kulcs beszerzésének folyamata:

  1. Ha az Always Encrypted engedélyezve van egy lekérdezéshez, az SQL Server Microsoft .NET-adatszolgáltatója transzparensen meghívja sys.sp_describe_parameter_encryption a titkosított oszlopokat megcélzó paraméterek titkosítási metaadatainak lekérésére, ha a lekérdezés rendelkezik paraméterekkel. A lekérdezés eredményeiben szereplő titkosított adatok esetében az SQL Server automatikusan csatolja a titkosítási metaadatokat. Az oszlop főkulcsával kapcsolatos információk a következők:

    • A kulcstároló-szolgáltató neve, amely egy kulcstárolót foglal magában, ami az oszlop főkulcsát tartalmazza.
    • A kulcs elérési útja, amely meghatározza az oszlop főkulcsának helyét a kulcstárolóban.

    Az oszloptitkosítási kulcsra vonatkozó információk a következők:

    • Az oszloptitkosítási kulcs titkosított értéke.
    • Az oszloptitkosítási kulcs titkosításához használt algoritmus neve.
  2. A SQL Serverhez készült Microsoft .NET Data Provider a oszlop mesterkulcs tároló szolgáltatójának nevét használja a szolgáltatói objektum megkeresésére, amely az SqlColumnEncryptionKeyStoreProvider osztályból származó osztály egy példánya egy belső adatstruktúrában.

  3. Az oszloptitkosítási kulcs visszafejtéséhez az SQL Server Microsoft .NET-adatszolgáltatója meghívja a SqlColumnEncryptionKeyStoreProvider.DecryptColumnEncryptionKey() metódust, átadva az oszlop főkulcsának elérési útját, az oszloptitkosítási kulcs titkosított értékét és a titkosított oszloptitkosítási kulcs előállításához használt titkosítási algoritmus nevét.

Beépített oszlop főkulcstároló-szolgáltatók használata

Az SQL Serverhez készült Microsoft .NET-adatszolgáltató a következő beépített oszlop főkulcstár szolgáltatókkal rendelkezik, amelyek előre regisztrálva vannak a megadott szolgáltatói nevekkel (a szolgáltató keresésére szolgálnak). Ezek a beépített kulcstároló-szolgáltatók csak Windows rendszeren támogatottak.

Class Description Szolgáltató (keresési) neve Plattform
SqlColumnEncryptionCertificateStoreProvider osztály A Windows Tanúsítványtároló szolgáltatója. MSSQL_CERTIFICATE_STORE Windows
SqlColumnEncryptionCngProvider osztály A Microsoft Cryptography API: Next Generation (CNG) API-t támogató kulcstár szolgáltatója. Az ilyen típusú tárolók általában hardveres biztonsági modulok – olyan fizikai eszközök, amelyek védik és kezelik a digitális kulcsokat, és kriptográfiai feldolgozást biztosítanak. MSSQL_CNG_STORE Windows
SqlColumnEncryptionCspProvider osztály A Microsoft Cryptography API (CAPI) használatát támogató kulcstár szolgáltatója. Az ilyen típusú tárolók általában hardveres biztonsági modulok – olyan fizikai eszközök, amelyek védik és kezelik a digitális kulcsokat, és kriptográfiai feldolgozást biztosítanak. MSSQL_CSP_PROVIDER Windows

A szolgáltatók használatához nem kell módosítania az alkalmazáskódokat, de jegyezze fel a következő részleteket:

  • Önnek (vagy a DBA-nak) meg kell győződnie arról, hogy az oszlop főkulcs metaadataiban konfigurált szolgáltatónév helyes, és az oszlop főkulcsának elérési útja megfelel az adott szolgáltatóra érvényes kulcsútvonal-formátumnak. Javasoljuk, hogy a kulcsokat olyan eszközökkel konfigurálja, mint az SQL Server Management Studio, amely automatikusan létrehozza az érvényes szolgáltatóneveket és kulcsútvonalakat a CREATE COLUMN MASTER KEY (Transact-SQL) utasítás kiadásakor. További információ: Always Encrypted konfigurálása az SQL Server Management Studióval és az Always Encrypted konfigurálása a PowerShell használatával.
  • Győződjön meg arról, hogy az alkalmazás hozzáfér a kulcstároló kulcsához. Ez a folyamat magában foglalhatja az alkalmazás hozzáférését a kulcshoz és/vagy a kulcstárolóhoz a kulcstárolótól függően, vagy más kulcstároló-specifikus konfigurációs lépések végrehajtásával. Ha például egy CNG-t vagy CAPI-t (például hardveres biztonsági modult) megvalósító kulcstárhoz szeretne hozzáférni, győződjön meg arról, hogy az áruházhoz tartozó CNG-t vagy CAPI-t implementáló kódtár telepítve van az alkalmazásgépen. További információ: Az Always Encrypted oszlop főkulcsainak létrehozása és tárolása.

Az Azure Key Vault-szolgáltató használata

Az Azure Key Vault egy kényelmes lehetőség az Always Encrypted oszlop-főkulcsainak tárolására és kezelésére (különösen akkor, ha az alkalmazások az Azure-ban vannak üzemeltetve). Az SQL ServerHez készült Microsoft .NET-adatszolgáltató nem tartalmaz beépített oszlop főkulcstár-szolgáltatót az Azure Key Vaulthoz, de NuGet-csomagként (Microsoft.Data.SqLClient.AlwaysEncrypted.AzureKeyVaultProvider) érhető el, amelyet egyszerűen integrálhat az alkalmazással. További részletekért lásd: Always Encrypted – Bizalmas adatok védelme az SQL Database-ben adattitkosítással, és a titkosítási kulcsok tárolása az Azure Key Vaultban.

Class Description Szolgáltató (keresési) neve Plattform
SqlColumnEncryptionAzureKeyVaultProvider osztály Az Azure Key Vault szolgáltatója. AZURE_KEY_VAULT Windows, Linux, macOS

.NET-támogatás

verzió Microsoft.Data.SqlClient-verzió .NET-platformok
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+

A 3.0.0-s verziótól kezdve az Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider oszloptitkosítási kulcs gyorsítótárazási képességei támogatottak a szolgáltató SqlConnection.RegisterColumnEncryptionKeyStoreProvidersOnConnection vagy SqlCommand.RegisterColumnEncryptionKeyStoreProvidersOnCommand API-k használatával történő regisztrálásakor.

A 2.0.0-s verziótól kezdve a rendszer támogatja az Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider új Azure.Core és Azure.Identity API-kat az Azure Key Vaulttal való hitelesítéshez. Az TokenCredential implementáció egy példánya most már átadható az SqlColumnEncryptionAzureKeyVaultProvider konstruktorainak az Azure Key Vault szolgáltatói objektum inicializálásához.

Megjegyzés:

A Microsoft.Data.SqLClient.AlwaysEncrypted.AzureKeyVaultProvidertárolók és a felügyelt HSM-ek is támogatottak az Azure Key Vaultban.

Az Azure Key Vaulttal való titkosítást/visszafejtést bemutató példákért tekintse meg az Azure Key Vault Always Encrypted ésaz Azure Key Vault biztonságos enklávékkal való használatát.

Egyéni oszlop főkulcstároló-szolgáltató implementálása

Ha olyan kulcstárolóban szeretné tárolni az oszlop főkulcsait, amelyet egy meglévő szolgáltató nem támogat, egyéni szolgáltatót implementálhat az SqlColumnEncryptionKeyStoreProvider osztály kibővítésével és a szolgáltató regisztrálásával az alábbi módszerek egyikével:

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);
        // ...
    }
}

Oszloptitkosítási kulcs gyorsítótárának elsőbbsége

Ez a szakasz az SQL Serverhez készült Microsoft .NET adatszolgáltató 3.0-s és újabb verziójára vonatkozik.

A kapcsolaton vagy parancspéldányon regisztrált egyéni kulcstároló-szolgáltatók által visszafejtette oszloptitkosítási kulcsokat (CEK) a Microsoft .NET SQL Server adatszolgáltató nem fogja gyorsítótározza. Az egyéni kulcstároló-szolgáltatóknak saját CEK-gyorsítótárazási mechanizmust kell implementálniuk.

A 3.0.0-s verziótól kezdve minden Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProviderpéldány Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider saját CEK gyorsítótárazási implementációval rendelkezik. Amikor CEK-eket regisztrálnak egy kapcsolat- vagy parancspéldányon, a Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider által visszafejtett CEK-ek törlődnek, amikor az adott példány kiesik a hatókörből.

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
        }
    }
}

Megjegyzés:

Az egyéni kulcstároló-szolgáltatók által megvalósított CEK-gyorsítótárazást az illesztőprogram letiltja, ha a kulcstároló-szolgáltató példánya globálisan regisztrálva van az illesztőprogramban az SqlConnection.RegisterColumnEncryptionKeyStoreProviders metódus használatával. A CEK gyorsítótárazásának bármely implementációjának hivatkoznia kell az SqlColumnEncryptionKeyStoreProvider.ColumnEncryptionKeyCacheTtl értékére a CEK gyorsítótárazása előtt, és nem kerül gyorsítótárazásra, ha az érték nulla. Ez segít elkerülni a duplikált gyorsítótárazást és a felhasználók esetleges zavarát, amikor kulcsgyorsítótárazást próbálnak konfigurálni.

Egyéni oszlopos főkulcs tároló szolgáltató regisztrálása

Ez a szakasz a szolgáltató 3.0-s és újabb verziójára vonatkozik.

Az egyéni főkulcstár-szolgáltatók három különböző rétegben regisztrálhatók az illesztőprogrammal. A három regisztráció elsőbbsége a következő:

  • A parancsonkénti regisztráció ellenőrizve lesz, ha nem üres.
  • Ha a parancsonkénti regisztráció üres, a rendszer ellenőrzi a kapcsolatonkénti regisztrációt, ha nem üres.
  • Ha a kapcsolatonkénti regisztráció üres, a rendszer ellenőrzi a globális regisztrációt.

Amint bármely kulcstároló-szolgáltatót megtalál a regisztrációs szinten, az illesztőprogram NEM fog visszatérni a többi regisztráció átnézésére, hogy szolgáltatót keressen. Ha a szolgáltatók regisztrálva vannak, de a megfelelő szolgáltató nem található egy szinten, a rendszer kivételt küld, amely csak az ellenőrzött regisztrációban szereplő regisztrált szolgáltatókat tartalmazza.

A Windows tanúsítványtárolóhoz, a CNG-tárolóhoz és a CSP-hez elérhető beépített oszlop főkulcstároló-szolgáltatók előre regisztrálva vannak.

A három regisztrációs szint különböző forgatókönyveket támogat a titkosított adatok lekérdezésekor. A megfelelő módszer használatával biztosítható, hogy egy alkalmazás felhasználója hozzáférhessen az egyszerű szöveges adatokhoz, ha meg tudja adni a szükséges fő oszlopkulcsot az oszlop főkulcsát tartalmazó kulcstároló hitelesítésével.

Azok az alkalmazások, amelyek több felhasználó között osztanak meg SqlConnection-példányt , érdemes lehet az SqlCommand.RegisterColumnEncryptionKeyStoreProvidersOnCommand parancsot használni. Minden felhasználónak regisztrálnia kell egy kulcstároló-szolgáltatót egy SqlCommand-példányon , mielőtt lekérdezést hajt végre egy titkosított oszlop eléréséhez. Ha a kulcstároló-szolgáltató a felhasználó megadott hitelesítő adataival hozzáfér a kulcstároló szükséges fő oszlopkulcsához, a lekérdezés sikeres lesz.

Az egyes felhasználókhoz SqlConnection-példányt létrehozó alkalmazások használhatják az SqlConnection.RegisterColumnEncryptionKeyStoreProvidersOnConnection parancsot. Az ezzel a módszerrel regisztrált kulcstároló-szolgáltatókat a kapcsolat használhatja a titkosított adatokat elérő lekérdezésekhez.

Az SqlConnection.RegisterColumnEncryptionKeyStoreProviders használatával regisztrált kulcstároló-szolgáltatók az alkalmazás által megadott identitást használják a kulcstárolóval való hitelesítéskor.

Az alábbi példa a kapcsolatpéldányon regisztrált egyéni oszlop főkulcstároló-szolgáltatóinak elsőbbségét mutatja be:

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

Az alábbi példa a parancspéldányon regisztrált egyéni oszlop főkulcstár-szolgáltatóinak elsőbbségét mutatja be:

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

Oszlop főkulcstároló-szolgáltatóinak használata programozott kulcsok kiépítéséhez

Amikor az SQL Server Microsoft .NET-adatszolgáltatója hozzáfér a titkosított oszlopokhoz, transzparens módon megkeresi és meghívja a megfelelő oszlop főkulcstároló-szolgáltatót az oszloptitkosítási kulcsok visszafejtéséhez. A normál alkalmazáskód általában nem hívja meg közvetlenül az oszlop főkulcstároló-szolgáltatóját. A szolgáltatót azonban explicit módon példányosíthatja és meghívhatja az Always Encrypted kulcsok programozott létrehozásához és kezeléséhez: titkosított oszloptitkosítási kulcs generálásához és egy oszloptitkosítási kulcs visszafejtéséhez (például az oszlop főkulcsának forgatásának részeként). További információ: Az Always Encrypted kulcskezelésének áttekintése. A saját kulcskezelési eszközök implementálása csak egyéni kulcstároló-szolgáltató használata esetén lehet szükséges. Ha kulcstárolókban tárolt kulcsokat használ, amelyekhez beépített szolgáltatók léteznek, vagy az Azure Key Vaultban, a meglévő eszközök, például az SQL Server Management Studio vagy a PowerShell használatával kezelheti és kiépítheti a kulcsokat. Az alábbi példa egy oszloptitkosítási kulcs generálását mutatja be, és az SqlColumnEncryptionCertificateStoreProvider osztály használatával titkosítja a kulcsot egy tanúsítvánnyal.

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

Az Always Encrypted teljesítményhatásának szabályozása

Mivel az Always Encrypted egy ügyféloldali titkosítási technológia, a legtöbb teljesítményterhelés az ügyféloldalon figyelhető meg, nem az adatbázisban. A titkosítási és visszafejtési műveletek költségein kívül az ügyféloldal egyéb teljesítményterhelési forrásai a következők:

  • A lekérdezési paraméterek metaadatainak lekéréséhez további oda-vissza utak az adatbázisba.
  • Egy oszlop főkulcstárának hívása az oszlop főkulcsának eléréséhez.

Ez a szakasz az SQL Serverhez készült Microsoft .NET-adatszolgáltató beépített teljesítményoptimalizálásait és a fenti két tényező teljesítményre gyakorolt hatását ismerteti.

A kérés körforgásainak szabályozása a lekérdezési paraméterek metaadatainak lekéréséhez

Ha az Always Encrypted engedélyezve van egy kapcsolathoz, az SQL Server Microsoft .NET-adatszolgáltatója alapértelmezés szerint meghívja sys.sp_describe_parameter_encryption minden paraméteres lekérdezéshez, és átadja a lekérdezési utasítást (paraméterértékek nélkül) az SQL Servernek. sys.sp_describe_parameter_encryption elemzi a lekérdezési utasítást, hogy kiderítse, van-e szükség paraméterek titkosítására, és ha igen, mindegyiknél visszaadja a titkosítással kapcsolatos információkat, amelyek lehetővé teszik az SQL Server Microsoft .NET-adatszolgáltatójának a paraméterértékek titkosítását. A fenti viselkedés magas szintű átláthatóságot biztosít az ügyfélalkalmazás számára. Az alkalmazásnak (és az alkalmazásfejlesztőnek) nem kell tudnia, hogy mely lekérdezések férnek hozzá a titkosított oszlopokhoz, mindaddig, amíg a titkosított oszlopokat megcélzó értékek a Microsoft .NET SQL Server-adatszolgáltatónak lesznek átadva SqlParameter-objektumokban.

Metaadat gyorsítótár lekérdezése

Az SQL Server Microsoft .NET-adatszolgáltatója gyorsítótárazza az egyes lekérdezési utasításokhoz tartozó sys.sp_describe_parameter_encryption eredményeit. Ha tehát ugyanazt a lekérdezési utasítást többször hajtja végre, az illesztőprogram csak egyszer hívja sys.sp_describe_parameter_encryption . A lekérdezési utasítások titkosítási metaadatainak gyorsítótárazása jelentősen csökkenti a metaadatok adatbázisból való lekérésének teljesítményköltségét. A gyorsítótárazás alapértelmezés szerint engedélyezve van. A paraméterek metaadatainak gyorsítótárazását letilthatja az SqlConnection.ColumnEncryptionQueryMetadataCacheEnabled tulajdonság "false" értékre állításával, de ezt nem ajánljuk, csak kivételes esetekben, mint az alábbi példa:

Vegyünk egy adatbázist, amely két különböző sémával rendelkezik: s1 és s2. Minden séma tartalmaz egy táblát ugyanazzal a névvel: t. A s1.t és s2.t táblák definíciói megegyeznek, kivéve a titkosítással kapcsolatos tulajdonságokat: A s1.t táblában a c oszlop nincs titkosítva, míg a s2.t titkosítva van. Az adatbázisnak két felhasználója van: u1 és u2. A u1 felhasználók alapértelmezett sémája a s1. Az alapértelmezett séma a u2 esetében a s2. A .NET-alkalmazások két kapcsolatot nyitnak meg az adatbázissal, megszemélyesítve a u1 felhasználót egy kapcsolaton, a u2 felhasználót pedig egy másik kapcsolaton. Az alkalmazás egy paraméterrel ellátott lekérdezést küld, amely a c oszlopot célozza meg a u1 felhasználó kapcsolatán keresztül (a lekérdezés nem adja meg a sémát, így az alapértelmezett felhasználói sémát feltételezi). Ezután az alkalmazás ugyanazt a lekérdezést küldi a felhasználó kapcsolatán u2 keresztül. Ha a lekérdezés metaadatainak gyorsítótárazása engedélyezve van, az első lekérdezés után a gyorsítótár olyan metaadatokkal lesz feltöltve, amelyek azt az c oszlopot jelzik, amelyet a lekérdezési paraméter célként használ, nincs titkosítva. Mivel a második lekérdezés azonos lekérdezési utasítással rendelkezik, a rendszer a gyorsítótárban tárolt információkat fogja használni. Ennek eredményeképpen az illesztőprogram a paraméter titkosítása nélkül küldi el a lekérdezést (ami helytelen, mivel a céloszlop s2.t.ctitkosítva van), így a paraméter egyszerű szöveges értéke kiszivárog a kiszolgálóra. A kiszolgáló észleli ezt az inkompatibilitást, és arra kényszeríti az illesztőprogramot, hogy frissítse a gyorsítótárat, így az alkalmazás transzparensen újraküldi a lekérdezést a helyesen titkosított paraméterértékkel. Ilyen esetben le kell tiltani a gyorsítótárazást, hogy ne szivárogjanak ki bizalmas értékek a kiszolgálóra.

Always Encrypted beállítása a lekérdezés szintjén

A paraméteres lekérdezések titkosítási metaadatainak lekérése teljesítményhatásának kezeléséhez az Always Encryptedet külön lekérdezésekhez is engedélyezheti, ahelyett, hogy a kapcsolatnál állítaná be. Így biztosítható, hogy sys.sp_describe_parameter_encryption csak olyan lekérdezések esetén legyen meghívva, amelyekről tudja, hogy a paraméterek titkosított oszlopokat céloznak. Vegye figyelembe azonban, hogy ezzel csökkenti a titkosítás átláthatóságát: ha módosítja az adatbázisoszlopok titkosítási tulajdonságait, előfordulhat, hogy módosítania kell az alkalmazás kódját, hogy igazodjon a séma változásaihoz.

Megjegyzés:

Az Always Encrypted lekérdezési szinten való beállítása korlátozza a paramétertitkosítás metaadatainak gyorsítótárazásának teljesítménybeli előnyeit.

Az egyes lekérdezések Always Encrypted viselkedésének szabályozásához az SqlCommand és az SqlCommandColumnEncryptionSetting konstruktorát kell használnia. Íme néhány hasznos irányelv:

  • Ha a legtöbb lekérdezés egy ügyfélalkalmazás hozzáférési titkosított oszlopokat hajt végre:
    • Állítsa az Oszloptitkosítás beállítása kapcsolatisztring-kulcsszót az Engedélyezett értékre.
    • Állítsa az SqlCommandColumnEncryptionSetting beállításátLetiltva értékre olyan egyes lekérdezések esetében, amelyek nem férnek hozzá a titkosított oszlopokhoz. Ez a beállítás letiltja az sys.sp_describe_parameter_encryption hívását és az eredményhalmaz értékeinek visszafejtésére tett kísérletet.
    • Állítsa az SqlCommandColumnEncryptionSetting értékét ResultSetOnly értékre olyan egyedi lekérdezések esetében, amelyek nem rendelkeznek titkosítást igénylő paraméterekkel, de titkosított oszlopokból kérnek le adatokat. Ez a beállítás letiltja a sys.sp_describe_parameter_encryption hívását, valamint a paramétertitkosítást. A lekérdezés képes lesz visszafejteni az eredményeket a titkosítási oszlopokból.
  • Ha az ügyfélalkalmazás által végrehajtott legtöbb lekérdezés nem fér hozzá a titkosított oszlopokhoz:
    • Állítsa az Oszloptitkosítás beállítása kapcsolati sztringkulcsot Letiltva értékre.
    • Az SqlCommandColumnEncryptionSetting beállítása engedélyezve van az olyan egyes lekérdezésekhez, amelyek rendelkeznek a titkosítandó paraméterekkel. Ez a beállítás lehetővé teszi a sys.sp_describe_parameter_encryption hívását és a titkosított oszlopokból lekért lekérdezési eredmények visszafejtést is.
    • Állítsa az SqlCommandColumnEncryptionSetting értéket ResultSetOnly értékre olyan lekérdezések esetében, amelyek nem rendelkeznek titkosítást igénylő paraméterekkel, de titkosított oszlopokból kérnek le adatokat. Ez a beállítás letiltja a sys.sp_describe_parameter_encryption hívását és a paramétertitkosítást. A lekérdezés képes lesz visszafejteni az eredményeket a titkosítási oszlopokból.

Az alábbi példában az Always Encrypted le van tiltva az adatbázis-kapcsolat esetében. Az alkalmazás problémáinak lekérdezése olyan paraméterrel rendelkezik, amely a nem titkosított LastName oszlopot célozza. A lekérdezés adatot kér le a titkosított SSN és BirthDate oszlopokból. Ilyen esetben nem szükséges meghívni sys.sp_describe_parameter_encryption a titkosítási metaadatok lekéréséhez. Azonban engedélyezni kell a lekérdezési eredmények visszafejtésének engedélyezését, hogy az alkalmazás egyszerű szöveges értékeket fogadhasson a két titkosított oszlopból. Ezt az SqlCommandColumnEncryptionSettingResultSetOnly beállítással biztosíthatja.

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());
            }
        }
    }
}

Oszloptitkosítási kulcs gyorsítótárazása

Az oszloptitkosítási kulcsok visszafejtéséhez az oszlop főkulcstárolójába irányuló hívások számának csökkentése érdekében az SQL Server Microsoft .NET-adatszolgáltatója gyorsítótárazza az egyszerű szöveges oszloptitkosítási kulcsokat a memóriában. Miután a szolgáltató megkapta a titkosított oszloptitkosítási kulcs értékét az adatbázis metaadataitól, az illesztő először megpróbálja megtalálni a titkosított kulcs értékének megfelelő egyszerű szöveges oszloptitkosítási kulcsot. Az illesztőprogram csak akkor hívja meg az oszlop főkulcsát tartalmazó kulcstárolót, ha nem találja a titkosított oszloptitkosítási kulcs értékét a gyorsítótárban.

A gyorsítótárbejegyzések biztonsági okokból egy konfigurálható élettartam-intervallum után törlődnek. Az alapértelmezett élettartam 2 óra. Ha szigorúbb biztonsági követelmények vonatkoznak arra, hogy mennyi ideig gyorsítótárazhatók az oszloptitkosítási kulcsok egyszerű szövegben az alkalmazásban, az SqlConnection.ColumnEncryptionKeyCacheTtl tulajdonság használatával módosíthatja.

Az SqlConnection.RegisterColumnEncryptionKeyStoreProvidersOnConnection és az SqlCommand.RegisterColumnEncryptionKeyStoreProvidersOnCommand használatával regisztrált egyéni kulcstárolók nem rendelkeznek az SQL Server Microsoft .NET-adatszolgáltatója által gyorsítótárazott visszafejtett oszloptitkosítási kulcsokkal. Ehelyett az egyéni kulcstároló-szolgáltatóknak saját gyorsítótárazási mechanizmust kell implementálniuk. Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider v3.0.0 és az újabb verziók saját gyorsítótárazási implementációval rendelkeznek.

Olyan forgatókönyvek támogatása érdekében, amelyekben ugyanazon alkalmazás különböző felhasználói több lekérdezést is végrehajthatnak, az egyéni kulcstároló-szolgáltatók leképezhetők egy felhasználóhoz, és regisztrálhatók az adott felhasználóra vonatkozó kapcsolaton vagy parancspéldányon. Az alábbi példa bemutatja, hogyan használható újra egy példány Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider ugyanazon felhasználó különböző SqlCommand objektumai között. Több lekérdezés során az oszloptitkosítási kulcs gyorsítótára megmarad, csökkentve a kulcstárolóba irányuló megkeresések számát.

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
    }
}

További védelem engedélyezése sérült SQL Server esetén

Az SQL Server Microsoft .NET-adatszolgáltatója alapértelmezés szerint az adatbázisrendszerre (SQL Server vagy Azure SQL Database) támaszkodik, hogy metaadatokat adjon meg arról, hogy az adatbázis mely oszlopait titkosítja és hogyan. A titkosítási metaadatok lehetővé teszik, hogy az SQL Server Microsoft .NET-adatszolgáltatója az alkalmazás bemenete nélkül titkosítsa a lekérdezési paramétereket és visszafejtse a lekérdezési eredményeket, ami jelentősen csökkenti az alkalmazásban szükséges módosítások számát. Ha azonban az SQL Server-folyamat sérül, és egy támadó módosítja az SQL Server által az SQL Server microsoft .NET-adatszolgáltatójának küldött metaadatokat, előfordulhat, hogy a támadó bizalmas adatokat tud ellopni. Ez a szakasz azokat az API-kat ismerteti, amelyek további szintű védelmet nyújtanak az ilyen típusú támadások ellen a csökkentett átláthatóság árán.

Paramétertitkosítás kényszerítése

Mielőtt az SQL Server Microsoft .NET-adatszolgáltatója paraméteres lekérdezést küld az SQL Servernek, megkéri az SQL Servert ( a sys.sp_describe_parameter_encryption meghívásával), hogy elemezze a lekérdezési utasítást, és adjon meg információkat arról, hogy a lekérdezés mely paramétereit kell titkosítani. Egy sérült SQL Server-példány félrevezetheti a Microsoft .NET-adatszolgáltatót az SQL Serverhez úgy, hogy metaadatokat küld, amelyek jelzik, hogy a paraméter nem céloz meg titkosított oszlopot, annak ellenére, hogy az oszlop titkosítva van az adatbázisban. Ennek eredményeképpen az SQL Server Microsoft .NET-adatszolgáltatója nem titkosítja a paraméter értékét, és egyszerű szövegként küldené el a sérült SQL Server-példánynak.

Az ilyen támadás megakadályozása érdekében egy alkalmazás true értékre állíthatja a paraméter SqlParameter.ForceColumnEncryption tulajdonságát . Ez a beállítás kivételt okoz az SQL Server Microsoft .NET-adatszolgáltatója számára , ha a kiszolgálótól kapott metaadatok azt jelzik, hogy a paramétert nem kell titkosítani.

Bár az SqlParameter.ForceColumnEncryption tulajdonság használata segít a biztonság javításában, az ügyfélalkalmazás titkosításának átláthatóságát is csökkenti. Ha úgy frissíti az adatbázis sémáját, hogy módosítsa a titkosított oszlopok készletét, előfordulhat, hogy az alkalmazást is módosítania kell.

Az alábbi kódminta az SqlParameter.ForceColumnEncryption tulajdonság használatával szemlélteti, hogy a társadalombiztosítási számokat ne lehessen egyszerű szövegben elküldeni az adatbázisba.

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.
    }
}

Megbízható oszlop főkulcs-elérési útjainak konfigurálása

Az SQL Server visszaadja a titkosítási metaadatokat azokhoz a lekérdezési paraméterekhez, amelyek titkosított oszlopokat céloznak meg, valamint azon eredményekhez, amelyeket titkosított oszlopokból kértek le. Ezek a metaadatok tartalmazzák az oszlop mesterkulcsának kulcsútvonalát, amely azonosítja a kulcstárolót és megmutatja a kulcs helyét a kulcstárolóban. Ha az SQL Server-példány biztonsága sérül, elküldheti az SQL Server Microsoft .NET-adatszolgáltatójának kulcsútvonalát a támadó által vezérelt helyre. Ez a folyamat a kulcstároló hitelesítő adatainak kiszivárgásához vezethet, ha a kulcstároló megköveteli az alkalmazás hitelesítését.

Az ilyen támadások megelőzése érdekében az alkalmazás az SqlConnection.ColumnEncryptionTrustedMasterKeyPaths tulajdonság használatával megadhatja egy adott kiszolgáló megbízható kulcsútvonalainak listáját. Ha az SQL Server Microsoft .NET-adatszolgáltatója a megbízható kulcs elérési útjának listáján kívül kap egy kulcsútvonalat, kivételt fog eredményezni.

Bár a megbízható kulcs elérési útjainak beállítása javítja az alkalmazás biztonságát, az oszlop főkulcsának elforgatásakor (amikor az oszlop főkulcsának elérési útja megváltozik) módosítania kell a kódot vagy/és az alkalmazás konfigurációját.

Az alábbi példa bemutatja, hogyan konfigurálhatók a megbízható oszlopfőkulcsok elérési útjai:

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

Titkosított adatok másolása az SqlBulkCopy használatával

Az SqlBulkCopy használatával az egyik táblában már titkosított és tárolt adatokat egy másik táblába másolhatja az adatok visszafejtése nélkül. Ehhez tegye a következőt:

  • Győződjön meg arról, hogy a céltábla titkosítási konfigurációja megegyezik a forrástábla konfigurációval. Különösen mindkét táblának ugyanazokkal az oszlopokkal kell rendelkeznie, és az oszlopokat ugyanazokkal a titkosítási típusokkal és ugyanazokkal a titkosítási kulcsokkal kell titkosítani. Ha a céloszlopok bármelyike másként van titkosítva, mint a megfelelő forrásoszlop, a másolási művelet után nem tudja visszafejteni a céltáblában lévő adatokat. Az adatok sérültek lesznek.
  • Konfigurálja mindkét adatbázis-kapcsolatot a forrástáblához és a céltáblához anélkül, hogy engedélyezve van az Always Encrypted.
  • Állítsa be a AllowEncryptedValueModifications beállítást (lásd: SqlBulkCopyOptions).

Megjegyzés:

A beállításnál körültekintően kell eljárni AllowEncryptedValueModifications. Ez a beállítás az adatbázis sérüléséhez vezethet, mert az SQL Server Microsoft .NET-adatszolgáltatója nem ellenőrzi, hogy az adatok valóban titkosítva van-e, vagy a titkosítási típussal, algoritmussal és kulccsal megfelelően van-e titkosítva, mint a céloszlop.

Íme egy példa, amely adatokat másol az egyik táblából a másikba. A SSN és BirthDate oszlopok feltételezhetően titkosítva vannak.

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-referencia

Névtér:Microsoft.Data.SqlClient

Szerelvény: Microsoft.Data.SqlClient.dll

Név Description
SqlColumnEncryptionCertificateStoreProvider osztály A Windows Tanúsítványtároló kulcstároló-szolgáltatója.
SqlColumnEncryptionCngProvider osztály A Microsoft Cryptography API: Next Generation (CNG) kulcstároló-szolgáltatója.
SqlColumnEncryptionCspProvider osztály A Microsoft CAPI-alapú titkosítási szolgáltatók (CSP) kulcstároló-szolgáltatója.
SqlColumnEncryptionKeyStoreProvider osztály A kulcstároló-szolgáltatók alaposztálya.
SqlCommandColumnEncryptionSetting Enumeration Az Always Encrypted viselkedésének szabályozására szolgáló beállítások az egyes lekérdezésekhez.
SqlConnectionAttestationProtocol Enumeration Az Igazolási protokoll értékét adja meg az Always Encrypted biztonságos enklávékkal való használatakor
SqlConnection oszlop titkosítási beállítás felsorolása Az adatbázis-kapcsolat titkosításának és visszafejtéséhez szükséges beállítások.
SqlConnectionStringBuilder.ColumnEncryptionSetting tulajdonság Lekéri és beállítja az Always Encryptedt a kapcsolati sztringben.
SqlConnection.ColumnEncryptionQueryMetadataCacheEnabled tulajdonság Engedélyezi és letiltja a titkosítási lekérdezés metaadatainak gyorsítótárazását.
SqlConnection.ColumnEncryptionKeyCacheTtl Property Lekéri és beállítja az oszloptitkosítási kulcs gyorsítótárában lévő bejegyzések élettartamát.
SqlConnection.ColumnEncryptionTrustedMasterKeyPaths Tulajdonság Lehetővé teszi az adatbázis-kiszolgáló megbízható kulcsútvonalainak listáját. Ha egy alkalmazás-lekérdezés feldolgozása során az illesztő olyan kulcselérési utat kap, amely nem szerepel a listán, a lekérdezés sikertelen lesz. Ez a tulajdonság további védelmet nyújt az olyan biztonsági támadások ellen, amelyek egy feltört SQL Servert érintenek, amely hamis kulcsútvonalakat biztosít, ami a kulcstároló hitelesítő adatainak kiszivárgásához vezethet.
SqlConnection.RegisztrálOszlopTitkosításiKulcsTárolóSzolgáltatókat metódus Lehetővé teszi egyéni kulcstároló-szolgáltatók regisztrálását. Ez egy szótár, amely a kulcstár-szolgáltató neveket a kulcstár-szolgáltató implementációkra térképezi.
SqlCommand Konstruktor (String, SqlConnection, SqlTransaction, SqlCommandColumnEncryptionSetting) Lehetővé teszi az Always Encrypted viselkedésének szabályozását az egyes lekérdezések esetében.
SqlParameter.ForceColumnEncryption tulajdonság Kényszeríti egy paraméter titkosítását. Ha az SQL Server tájékoztatja az illesztőprogramot, hogy a paramétert nem kell titkosítani, a paramétert használó lekérdezés sikertelen lesz. Ez a tulajdonság további védelmet nyújt az olyan biztonsági támadások ellen, amelyek egy sérült SQL Servert érintenek, amely helytelen titkosítási metaadatokat biztosít az ügyfélnek, ami adatfeltárást eredményezhet.
kapcsolati sztring kulcsszó: Column Encryption Setting=enabled Engedélyezi vagy letiltja az Always Encrypted funkciót a kapcsolathoz.

Lásd még