Menggunakan Always Encrypted dengan Penyedia Data Microsoft .NET untuk SQL Server

Berlaku untuk: .NET Framework .NET .NET Standard

Artikel ini menyediakan informasi tentang cara mengembangkan aplikasi .NET menggunakan Always Encrypted atau Always Encrypted dengan enklave aman dan Penyedia Data .NET Microsoft untuk SQL Server.

Always Encrypted memungkinkan aplikasi klien mengenkripsi data sensitif dan tidak pernah mengungkapkan data atau kunci enkripsi ke SQL Server atau Azure SQL Database. Driver yang diaktifkan Always Encrypted, seperti Penyedia Data .NET Microsoft untuk SQL Server, mencapai keamanan ini dengan mengenkripsi dan mendekripsi data sensitif secara transparan di aplikasi klien. Driver secara otomatis menentukan parameter kueri mana yang sesuai dengan kolom database sensitif (dilindungi menggunakan Always Encrypted), dan mengenkripsi nilai parameter tersebut sebelum meneruskan data ke server. Demikian pula, driver secara transparan mendekripsi data yang diambil dari kolom database terenkripsi dalam hasil kueri. Untuk informasi selengkapnya, lihat Mengembangkan aplikasi menggunakan Always Encrypted dan Mengembangkan aplikasi menggunakan Always Encrypted dengan enklave aman.

Prasyarat

  • Konfigurasikan Always Encrypted di database Anda. Proses ini melibatkan penyediaan kunci Always Encrypted dan menyiapkan enkripsi untuk kolom database yang dipilih. Jika Anda belum memiliki database dengan Always Encrypted yang dikonfigurasi, ikuti petunjuk dalam Tutorial: Memulai Always Encrypted.
  • Jika Anda menggunakan Always Encrypted dengan enklave aman, lihat Mengembangkan aplikasi menggunakan Always Encrypted dengan enklave aman untuk prasyarat lainnya.
  • Pastikan platform .NET yang diperlukan diinstal pada komputer pengembangan Anda. Dengan Microsoft.Data.SqlClient, fitur Always Encrypted didukung untuk .NET Framework dan .NET Core. Pastikan .NET Framework 4.6 atau yang lebih tinggi, atau .NET Core 2.1 atau yang lebih tinggi dikonfigurasi sebagai versi platform .NET target di lingkungan pengembangan Anda. Dengan Microsoft.Data.SqlClient versi 2.1.0 dan yang lebih tinggi, fitur Always Encrypted juga didukung untuk .NET Standard 2.0. Untuk menggunakan Always Encrypted dengan enklave aman, diperlukan .NET Standard 2.1 . Jika Anda ingin menggunakan enklave VBS tanpa pengesahan, Microsoft.Data.SqlClient versi 4.1 atau yang lebih tinggi diperlukan. Jika Anda menggunakan Visual Studio, lihat Ringkasan penargetan Kerangka Kerja.

Tabel berikut ini meringkas platform .NET yang diperlukan untuk menggunakan Always Encrypted dengan Microsoft.Data.SqlClient.

Dukungan Always Encrypted Mendukung Always Encrypted dengan Secure Enclave Kerangka Target Versi Microsoft.Data.SqlClient Sistem Operasi
Ya Ya .NET Framework 4.6+ 1.1.0+ Windows
Ya Ya .NET Core 2.1+ 2.1.0+1 Windows, Linux, macOS
Ya Tidak .NET Standar 2.0 2.1.0+ Windows, Linux, macOS
Ya Ya .NET Standar 2.1+ 2.1.0+ Windows, Linux, macOS

Catatan

1 Sebelum Microsoft.Data.SqlClient versi 2.1.0, Always Encrypted hanya didukung di Windows.

Mengaktifkan Always Encrypted untuk kueri aplikasi

Cara term mudah untuk mengaktifkan enkripsi parameter dan dekripsi hasil kueri yang menargetkan kolom terenkripsi, adalah dengan mengatur nilai Column Encryption Setting kata kunci string koneksi untuk diaktifkan.

Contoh berikut menggunakan string koneksi yang mengaktifkan Always Encrypted:

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

Cuplikan kode berikut adalah contoh yang setara menggunakan Properti Sql Koneksi ionStringBuilder.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 juga dapat diaktifkan untuk kueri individual. Lihat bagian Mengontrol dampak performa Always Encrypted di bawah ini. Mengaktifkan Always Encrypted tidak cukup untuk enkripsi atau dekripsi agar berhasil. Anda juga perlu memastikan:

  • Aplikasi ini memiliki izin database VIEW ANY COLUMN MASTER KEY DEFINITION dan VIEW ANY COLUMN ENCRYPTION KEY DEFINITION , yang diperlukan untuk mengakses metadata tentang kunci Always Encrypted dalam database. Untuk detailnya, lihat bagian Izin Database di Always Encrypted (Mesin Database).
  • Aplikasi dapat mengakses kunci master kolom yang melindungi kunci enkripsi kolom, yang mengenkripsi kolom database yang dikueri.

Mengaktifkan Always Encrypted dengan enklave aman

Dimulai dengan Microsoft.Data.SqlClient versi 1.1.0, driver mendukung Always Encrypted dengan enklave aman.

Untuk informasi umum tentang mengembangkan aplikasi menggunakan enklave, lihat Mengembangkan aplikasi menggunakan Always Encrypted dengan enklave aman.

Untuk mengaktifkan komputasi enklave untuk koneksi database, Anda harus mengatur kata kunci string koneksi berikut, selain mengaktifkan Always Encrypted (seperti yang dijelaskan di bagian sebelumnya):

  • Attestation Protocol - menentukan protokol pengesahan.

    • Jika kata kunci ini tidak ditentukan, enklave aman dinonaktifkan pada koneksi.
    • Jika Anda menggunakan SQL Server dengan enklave keamanan berbasis Virtualisasi (VBS) dan Host Guardian Service (HGS), nilai kata kunci ini harus HGS.
    • Jika Anda menggunakan Azure SQL Database dengan enklave Intel SGX dan Microsoft Azure Attestation, nilai kata kunci ini harus .AAS
    • Jika Anda menggunakan Azure SQL Database atau SQL Server dengan enklave VBS dan ingin melakukan pengesahan forgo, nilai kata kunci ini harus None. Memerlukan versi 4.1 atau yang lebih tinggi.

    Catatan

    'None' (tanpa pengesahan) adalah satu-satunya opsi yang saat ini didukung untuk enklave VBS di Azure SQL Database.

  • Enclave Attestation URL - menentukan URL pengesahan (titik akhir layanan pengesahan). Anda perlu mendapatkan URL pengesahan untuk lingkungan Anda dari administrator layanan pengesahan Anda.

Untuk tutorial langkah demi langkah, lihat Tutorial: Mengembangkan aplikasi .NET menggunakan Always Encrypted dengan enklave aman.

Mengambil dan memodifikasi data dalam kolom terenkripsi

Setelah mengaktifkan Always Encrypted untuk kueri aplikasi, Anda dapat menggunakan API SqlClient standar (lihat Mengambil dan Memodifikasi Data dalam ADO.NET) atau Penyedia Data Microsoft .NET untuk API SQL Server , yang ditentukan dalam Namespace Microsoft.Data.SqlClient, untuk mengambil atau memodifikasi data dalam kolom database terenkripsi. Jika aplikasi Anda memiliki izin database yang diperlukan dan dapat mengakses kunci master kolom, Penyedia Data .NET Microsoft untuk SQL Server akan mengenkripsi parameter kueri apa pun yang menargetkan kolom terenkripsi, dan akan mendekripsi data yang diambil dari kolom terenkripsi, mengembalikan nilai teks biasa dari jenis .NET yang sesuai dengan jenis data SQL Server yang ditetapkan untuk kolom dalam skema database. Jika Always Encrypted tidak diaktifkan, kueri dengan parameter yang menargetkan kolom terenkripsi akan gagal. Kueri masih dapat mengambil data dari kolom terenkripsi selama kueri tidak memiliki parameter yang menargetkan kolom terenkripsi. Namun, Penyedia Data .NET Microsoft untuk SQL Server tidak akan mencoba mendekripsi nilai apa pun yang diambil dari kolom terenkripsi dan aplikasi akan menerima data terenkripsi biner (sebagai array byte).

Tabel berikut ini meringkas perilaku kueri, bergantung pada apakah Always Encrypted diaktifkan atau tidak:

Karakteristik kueri Always Encrypted diaktifkan dan aplikasi dapat mengakses kunci dan metadata kunci Always Encrypted diaktifkan dan aplikasi tidak dapat mengakses kunci atau metadata kunci Always Encrypted dinonaktifkan
Kueri dengan parameter yang menargetkan kolom terenkripsi. Nilai parameter dienkripsi secara transparan. Kesalahan Kesalahan
Kueri mengambil data dari kolom terenkripsi tanpa parameter yang menargetkan kolom terenkripsi. Hasil dari kolom terenkripsi didekripsi secara transparan. Aplikasi menerima nilai teks biasa dari jenis data .NET yang sesuai dengan jenis SQL Server yang dikonfigurasi untuk kolom terenkripsi. Kesalahan Hasil dari kolom terenkripsi tidak didekripsi. Aplikasi menerima nilai terenkripsi sebagai array byte (byte[]).

Contoh berikut mengilustrasikan pengambilan dan modifikasi data dalam kolom terenkripsi. Contoh mengasumsikan tabel target dengan skema di bawah ini. Kolom SSN dan BirthDate dienkripsi.

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

Menyisipkan contoh data

Contoh ini menyisipkan baris ke dalam tabel Pasien. Perhatikan detail berikut:

  • Tidak ada yang spesifik untuk enkripsi dalam kode sampel. Penyedia Data .NET Microsoft untuk SQL Server secara otomatis mendeteksi dan mengenkripsi paramSSN parameter dan paramBirthdate yang menargetkan kolom terenkripsi. Perilaku ini membuat enkripsi transparan ke aplikasi.
  • Nilai yang disisipkan ke dalam kolom database, termasuk kolom terenkripsi, diteruskan sebagai objek SqlParameter . Saat menggunakan SqlParameter bersifat opsional saat mengirim nilai ke kolom yang tidak dienkripsi (meskipun, sangat disarankan karena membantu mencegah injeksi SQL), diperlukan untuk nilai yang menargetkan kolom terenkripsi. Jika nilai yang disisipkan dalam kolom atau diteruskan SSN sebagai harfiah yang disematkan dalam pernyataan kueri, kueri akan gagal karena Penyedia Data .NET Microsoft untuk SQL Server tidak akan dapat menentukan nilai dalam kolom terenkripsi target, sehingga tidak akan mengenkripsi nilai.BirthDate Akibatnya, server akan menolaknya sebagai tidak kompatibel dengan kolom terenkripsi.
  • Jenis data parameter yang menargetkan SSN kolom diatur ke string ANSI (non-Unicode), yang memetakan ke jenis data char/varchar SQL Server. Jika jenis parameter diatur ke string Unicode (String), yang memetakan ke nchar/nvarchar, kueri akan gagal, karena Always Encrypted tidak mendukung konversi dari nilai nchar/nvarchar terenkripsi ke nilai char/varchar terenkripsi. Lihat Pemetaan Tipe Data SQL Server untuk informasi tentang pemetaan jenis data.
  • Jenis data parameter yang dimasukkan ke dalam BirthDate kolom secara eksplisit diatur ke jenis data SQL Server target menggunakan Properti SqlParameter.SqlDbType, alih-alih mengandalkan pemetaan implisit jenis .NET ke jenis data SQL Server yang diterapkan saat menggunakan Properti SqlParameter.DbType. Secara default, Struktur DateTime memetakan ke jenis data SQL Server datetime. Karena jenis BirthDate data kolom adalah tanggal dan Always Encrypted tidak mendukung konversi nilai tanggalwaktu terenkripsi ke nilai tanggal terenkripsi, menggunakan pemetaan default akan mengakibatkan kesalahan.
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();
}

Mengambil contoh data teks biasa

Contoh berikut menunjukkan pemfilteran data berdasarkan nilai terenkripsi dan mengambil data teks biasa dari kolom terenkripsi.

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

Catatan

  • Nilai yang digunakan dalam klausul WHERE untuk memfilter kolom perlu diteruskan SSN menggunakan SqlParameter, sehingga Penyedia Data Microsoft .NET untuk SQL Server dapat mengenkripsinya secara transparan sebelum mengirimkannya ke database.

  • Semua nilai yang dicetak oleh program akan berada dalam teks biasa, karena Penyedia Data .NET Microsoft untuk SQL Server akan secara transparan mendekripsi data yang diambil dari SSN kolom dan BirthDate .

  • Kueri dapat melakukan perbandingan kesetaraan pada kolom jika dienkripsi menggunakan enkripsi deterministik.

Mengambil contoh data terenkripsi

Jika Always Encrypted tidak diaktifkan, kueri masih dapat mengambil data dari kolom terenkripsi, selama kueri tidak memiliki parameter yang menargetkan kolom terenkripsi.

Contoh berikut menunjukkan cara mengambil data terenkripsi biner dari kolom terenkripsi.

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

Catatan

  • Karena Always Encrypted tidak diaktifkan dalam string koneksi, kueri akan mengembalikan nilai terenkripsi dan SSNBirthDate sebagai array byte (program mengonversi nilai menjadi string).

  • Kueri yang mengambil data dari kolom terenkripsi dengan Always Encrypted dinonaktifkan dapat memiliki parameter, selama tidak ada parameter yang menargetkan kolom terenkripsi. Filter kueri di atas menurut LastName, yang tidak dienkripsi dalam database. Jika kueri difilter menurut SSN atau BirthDate, kueri akan gagal.

Menghindari masalah umum saat mengkueri kolom terenkripsi

Bagian ini menjelaskan kategori kesalahan umum saat mengkueri kolom terenkripsi dari aplikasi .NET dan beberapa panduan tentang cara menghindarinya.

Kesalahan konversi jenis data yang tidak didukung

Always Encrypted mendukung beberapa konversi untuk jenis data terenkripsi. Lihat Always Encrypted untuk daftar terperinci konversi jenis yang didukung. Lakukan hal berikut untuk menghindari kesalahan konversi jenis data:

  • Atur jenis parameter yang menargetkan kolom terenkripsi sehingga jenis data SQL Server parameter sama persis dengan jenis kolom target, atau konversi jenis data SQL Server dari parameter ke jenis target kolom didukung. Anda dapat menerapkan pemetaan jenis data .NET yang diinginkan ke jenis data SQL Server tertentu dengan menggunakan Properti SqlParameter.SqlDbType.
  • Verifikasi presisi dan skala parameter yang menargetkan kolom dari jenis data SQL Server desimal dan numerik sama dengan presisi dan skala yang dikonfigurasi untuk kolom target.
  • Verifikasi presisi parameter yang menargetkan kolom jenis data datetime2, datetimeoffset, atau time SQL Server tidak lebih besar dari presisi untuk kolom target (dalam kueri yang memodifikasi nilai di kolom target).

Kesalahan karena meneruskan teks biasa alih-alih nilai terenkripsi

Nilai apa pun yang menargetkan kolom terenkripsi perlu dienkripsi di dalam aplikasi. Upaya untuk menyisipkan/memodifikasi atau memfilter berdasarkan nilai teks biasa pada kolom terenkripsi akan mengakibatkan kesalahan seperti ini:

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'

Untuk mencegah kesalahan tersebut, pastikan:

  • Always Encrypted diaktifkan untuk kueri aplikasi yang menargetkan kolom terenkripsi (untuk string koneksi atau di objek SqlCommand untuk kueri tertentu).
  • Anda menggunakan SqlParameter untuk mengirim data yang menargetkan kolom terenkripsi. Contoh berikut menunjukkan kueri yang salah memfilter menurut harfiah/konstanta pada kolom terenkripsi (SSN) alih-alih meneruskan literal di dalam objek SqlParameter.
using (SqlCommand cmd = connection.CreateCommand())
{
    cmd.CommandText = @"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE SSN = '795-73-9838'";
    cmd.ExecuteNonQuery();
}

Bekerja dengan penyimpanan kunci master kolom

Untuk mengenkripsi nilai parameter atau untuk mendekripsi data dalam hasil kueri, Penyedia Data .NET Microsoft untuk SQL Server perlu mendapatkan kunci enkripsi kolom yang dikonfigurasi untuk kolom target. Kunci enkripsi kolom disimpan dalam formulir terenkripsi dalam metadata database. Setiap kunci enkripsi kolom memiliki kunci master kolom terkait yang digunakan untuk mengenkripsi kunci enkripsi kolom. Metadata database tidak menyimpan kunci master kolom - metadata hanya berisi informasi tentang penyimpanan kunci yang berisi kunci master kolom tertentu dan lokasi kunci di penyimpanan kunci.

Untuk mendapatkan nilai teks biasa dari kunci enkripsi kolom, Penyedia Data .NET Microsoft untuk SQL Server terlebih dahulu mendapatkan metadata tentang kunci enkripsi kolom dan kunci master kolom yang sesuai. Kemudian menggunakan informasi dalam metadata untuk menghubungi penyimpanan kunci yang berisi kunci master kolom, dan untuk mendekripsi kunci enkripsi kolom terenkripsi. Penyedia Data Microsoft .NET untuk SQL Server berkomunikasi dengan penyimpanan kunci menggunakan penyedia penyimpanan kunci master kolom - yang merupakan instans kelas yang berasal dari kelas SqlColumnEncryptionKeyStoreProvider.

Proses untuk mendapatkan kunci enkripsi kolom:

  1. Jika Always Encrypted diaktifkan untuk kueri, Penyedia Data Microsoft .NET untuk SQL Server secara transparan memanggil sys.sp_describe_parameter_encryption untuk mengambil metadata enkripsi untuk parameter yang menargetkan kolom terenkripsi, jika kueri memiliki parameter. Untuk data terenkripsi yang terkandung dalam hasil kueri, SQL Server secara otomatis melampirkan metadata enkripsi. Informasi tentang kunci master kolom meliputi:

    • Nama penyedia penyimpanan kunci yang merangkum penyimpanan kunci yang berisi kunci master kolom.
    • Jalur kunci yang menentukan lokasi kunci master kolom di penyimpanan kunci.

    Informasi tentang kunci enkripsi kolom meliputi:

    • Nilai terenkripsi kunci enkripsi kolom.
    • Nama algoritma yang digunakan untuk mengenkripsi kunci enkripsi kolom.
  2. Penyedia Data Microsoft .NET untuk SQL Server menggunakan nama penyedia penyimpanan kunci master kolom untuk mencari objek penyedia, yang merupakan instans kelas yang berasal dari kelas SqlColumnEncryptionKeyStoreProvider, dalam struktur data internal.

  3. Untuk mendekripsi kunci enkripsi kolom, Penyedia Data Microsoft .NET untuk SQL Server memanggil SqlColumnEncryptionKeyStoreProvider.DecryptColumnEncryptionKey() metode , melewati jalur kunci master kolom, nilai terenkripsi kunci enkripsi kolom, dan nama algoritma enkripsi yang digunakan untuk menghasilkan kunci enkripsi kolom terenkripsi.

Menggunakan penyedia penyimpanan kunci master kolom bawaan

Penyedia Data Microsoft .NET untuk SQL Server dilengkapi dengan penyedia penyimpanan kunci master kolom bawaan berikut, yang telah didaftarkan sebelumnya dengan nama penyedia tertentu (digunakan untuk mencari penyedia). Penyedia penyimpanan kunci bawaan ini hanya didukung di Windows.

Kelas Deskripsi Nama penyedia (pencarian) Platform
Kelas SqlColumnEncryptionCertificateStoreProvider Penyedia untuk Penyimpanan Sertifikat Windows. MSSQL_CERTIFICATE_STORE Windows
Kelas SqlColumnEncryptionCngProvider Penyedia untuk penyimpanan kunci yang mendukung MICROSOFT Cryptography API: Next Generation (CNG) API. Biasanya, penyimpanan jenis ini adalah modul keamanan perangkat keras - perangkat fisik yang melindungi dan mengelola kunci digital dan menyediakan pemrosesan kripto. MSSQL_CNG_STORE Windows
Kelas SqlColumnEncryptionCspProvider Penyedia untuk penyimpanan kunci yang mendukung Microsoft Cryptography API (CAPI). Biasanya, penyimpanan jenis ini adalah modul keamanan perangkat keras - perangkat fisik yang melindungi dan mengelola kunci digital dan menyediakan pemrosesan kripto. MSSQL_CSP_PROVIDER Windows

Anda tidak perlu membuat perubahan kode aplikasi apa pun untuk menggunakan penyedia ini, tetapi perhatikan detail berikut:

  • Anda (atau DBA Anda) perlu memastikan nama penyedia, dikonfigurasi dalam metadata kunci master kolom, sudah benar dan jalur kunci master kolom mematuhi format jalur kunci yang valid untuk penyedia tertentu. Disarankan agar Anda mengonfigurasi kunci menggunakan alat seperti SQL Server Management Studio, yang secara otomatis menghasilkan nama penyedia dan jalur kunci yang valid saat mengeluarkan pernyataan CREATE COLUMN MASTER KEY (Transact-SQL). Untuk informasi selengkapnya, lihat Mengonfigurasi Always Encrypted menggunakan SQL Server Management Studio dan Mengonfigurasi Always Encrypted menggunakan PowerShell.
  • Pastikan aplikasi Anda dapat mengakses kunci di penyimpanan kunci. Proses ini mungkin melibatkan pemberian akses aplikasi Anda ke kunci dan/atau penyimpanan kunci, tergantung pada penyimpanan kunci, atau melakukan langkah-langkah konfigurasi khusus penyimpanan kunci lainnya. Misalnya, untuk mengakses penyimpanan kunci yang menerapkan CNG atau CAPI (seperti modul keamanan perangkat keras), Anda perlu memastikan pustaka yang menerapkan CNG atau CAPI untuk toko Anda diinstal di komputer aplikasi Anda. Untuk detailnya, lihat Membuat dan menyimpan kunci master kolom untuk Always Encrypted.

Menggunakan penyedia Azure Key Vault

Azure Key Vault adalah opsi yang mudah untuk menyimpan dan mengelola kunci master kolom untuk Always Encrypted (terutama jika aplikasi Anda dihosting di Azure). Penyedia Data Microsoft .NET untuk SQL Server tidak menyertakan penyedia penyimpanan kunci master kolom bawaan untuk Azure Key Vault, tetapi tersedia sebagai paket NuGet (Microsoft.Data.SqLClient.AlwaysEncrypted.AzureKeyVaultProvider) yang dapat Anda integrasikan dengan aplikasi Anda dengan mudah. Untuk detailnya, lihat Always Encrypted - Melindungi data sensitif di SQL Database dengan enkripsi data dan menyimpan kunci enkripsi Anda di Azure Key Vault.

Kelas Deskripsi Nama penyedia (pencarian) Platform
SqlColumnEncryptionAzureKeyVaultProvider Class Penyedia untuk Azure Key Vault. AZURE_KEY_VAULT Windows, Linux, macOS

Dukungan .NET

Versi Versi Microsoft.Data.SqlClient Platform .NET
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+

Dimulai dengan v3.0.0, Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider mendukung kemampuan penembolokan kunci enkripsi kolom saat mendaftarkan penyedia menggunakan Sql Koneksi ion. RegisterColumnEncryptionKeyStoreProvidersOn Koneksi ion atau SqlCommand.RegisterColumnEncryptionKeyStoreProvidersOnCommand API.

Dimulai dengan v2.0.0, Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider mendukung API dan Azure.Identity baru Azure.Core untuk melakukan autentikasi dengan Azure Key Vault. Instans TokenCredential implementasi sekarang dapat diteruskan ke SqlColumnEncryptionAzureKeyVaultProvider konstruktor untuk menginisialisasi objek penyedia Azure Key Vault.

Catatan

Mendukung Microsoft.Data.SqLClient.AlwaysEncrypted.AzureKeyVaultProviderVault dan HSM Terkelola di Azure Key Vault.

Untuk contoh yang menunjukkan enkripsi/dekripsi dengan Azure Key Vault, lihat Azure Key Vault yang bekerja dengan Always Encrypted dan Azure Key Vault yang bekerja dengan Always Encrypted dengan enklave aman.

Menerapkan penyedia penyimpanan kunci master kolom kustom

Jika Anda ingin menyimpan kunci master kolom di penyimpanan kunci yang tidak didukung oleh penyedia yang ada, Anda dapat menerapkan penyedia kustom dengan memperluas kelas SqlColumnEncryptionKeyStoreProvider dan mendaftarkan penyedia menggunakan salah satu metode berikut:

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

Prioritas cache kunci enkripsi kolom

Bagian ini berlaku untuk Microsoft .NET Data Provider untuk SQL Server versi 3.0 dan yang lebih tinggi.

Kunci enkripsi kolom (CEK) yang didekripsi oleh penyedia penyimpanan kunci kustom yang terdaftar pada koneksi atau instans perintah tidak akan di-cache oleh Penyedia Data Microsoft .NET untuk SQL Server. Penyedia penyimpanan kunci kustom harus menerapkan mekanisme penembolokan CEK mereka sendiri.

Dimulai dengan v3.0.0 dari Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider, setiap instans Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider memiliki implementasi penembolokan CEK sendiri. Ketika terdaftar pada koneksi atau instans perintah, CEK yang didekripsi oleh instans Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider akan dihapus ketika instans tersebut keluar dari cakupan:

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

Catatan

Penembolokan CEK yang diterapkan oleh penyedia penyimpanan kunci kustom akan dinonaktifkan oleh driver jika instans penyedia penyimpanan kunci terdaftar di driver secara global menggunakan Sql Koneksi ion. Metode RegisterColumnEncryptionKeyStoreProviders. Implementasi penembolokan CEK apa pun harus mereferensikan nilai SqlColumnEncryptionKeyStoreProvider.ColumnEncryptionKeyCacheTtl sebelum membuat cache CEK dan tidak menyimpannya jika nilainya nol. Ini akan menghindari penembolokan duplikat dan kemungkinan kebingungan pengguna saat mereka mencoba mengonfigurasi penembolokan kunci.

Mendaftarkan penyedia penyimpanan kunci master kolom kustom

Bagian ini berlaku untuk penyedia versi 3.0 dan yang lebih tinggi.

Penyedia penyimpanan kunci master kustom dapat didaftarkan dengan driver pada tiga lapisan yang berbeda. Prioritas dari tiga pendaftaran adalah sebagai berikut:

  • Pendaftaran per perintah akan diperiksa jika tidak kosong.
  • Jika pendaftaran per perintah kosong, pendaftaran per koneksi akan diperiksa jika tidak kosong.
  • Jika pendaftaran per koneksi kosong, pendaftaran global akan diperiksa.

Setelah penyedia penyimpanan kunci ditemukan pada tingkat pendaftaran, driver TIDAK akan kembali ke pendaftaran lain untuk mencari penyedia. Jika penyedia terdaftar tetapi penyedia yang tepat tidak ditemukan pada tingkat, pengecualian akan dilemparkan hanya berisi penyedia terdaftar dalam pendaftaran yang diperiksa.

Penyedia penyimpanan kunci master kolom bawaan yang tersedia untuk Windows Certificate Store, CNG Store, dan CSP telah didaftarkan sebelumnya.

Tiga tingkat pendaftaran mendukung skenario yang berbeda saat mengkueri data terenkripsi. Metode yang sesuai dapat digunakan untuk memastikan bahwa pengguna aplikasi dapat mengakses data teks biasa jika mereka dapat menyediakan kunci master kolom yang diperlukan, dengan mengautentikasi terhadap penyimpanan kunci yang berisi kunci master kolom.

Aplikasi yang berbagi instans Sql Koneksi ion antara beberapa pengguna mungkin ingin menggunakan SqlCommand.RegisterColumnEncryptionKeyStoreProvidersOnCommand. Setiap pengguna harus mendaftarkan penyedia penyimpanan kunci pada instans SqlCommand sebelum menjalankan kueri untuk mengakses kolom terenkripsi. Jika penyedia penyimpanan kunci dapat mengakses kunci master kolom yang diperlukan di penyimpanan kunci menggunakan kredensial yang diberikan pengguna, kueri akan berhasil.

Aplikasi yang membuat instans Sql Koneksi ion untuk setiap pengguna mungkin ingin menggunakan Sql Koneksi ion. RegisterColumnEncryptionKeyStoreProvidersOn Koneksi ion. Penyedia penyimpanan kunci yang terdaftar dengan metode ini dapat digunakan oleh koneksi untuk setiap kueri yang mengakses data terenkripsi.

Penyedia penyimpanan kunci terdaftar menggunakan Sql Koneksi ion. RegisterColumnEncryptionKeyStoreProviders akan menggunakan identitas yang diberikan oleh aplikasi saat mengautentikasi terhadap penyimpanan kunci.

Contoh berikut menunjukkan prioritas penyedia penyimpanan kunci master kolom kustom yang terdaftar pada instans koneksi:

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

Contoh berikut menunjukkan prioritas penyedia penyimpanan kunci master kolom kustom yang terdaftar pada instans perintah:

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

Menggunakan penyedia penyimpanan kunci master kolom untuk provisi kunci terprogram

Ketika Penyedia Data .NET Microsoft untuk SQL Server mengakses kolom terenkripsi, penyedia penyimpanan kunci master kolom yang tepat secara transparan menemukan dan memanggil penyedia penyimpanan kunci master kolom yang tepat untuk mendekripsi kunci enkripsi kolom. Biasanya, kode aplikasi normal Anda tidak langsung memanggil penyedia penyimpanan kunci master kolom. Namun, Anda dapat membuat instans dan memanggil penyedia secara eksplisit untuk membuat dan mengelola kunci Always Encrypted secara terprogram: untuk menghasilkan kunci enkripsi kolom terenkripsi dan mendekripsi kunci enkripsi kolom (misalnya, sebagai rotasi kunci master kolom bagian). Untuk informasi selengkapnya, lihat Gambaran Umum manajemen kunci untuk Always Encrypted. Menerapkan alat manajemen kunci Anda sendiri mungkin diperlukan hanya jika Anda menggunakan penyedia penyimpanan kunci kustom. Saat menggunakan kunci yang disimpan di penyimpanan kunci, penyedia bawaan mana yang ada, dan atau di Azure Key Vault, Anda dapat menggunakan alat yang ada, seperti SQL Server Management Studio atau PowerShell, untuk mengelola dan menyediakan kunci. Contoh di bawah ini, menggambarkan pembuatan kunci enkripsi kolom dan menggunakan kelas SqlColumnEncryptionCertificateStoreProvider untuk mengenkripsi kunci dengan sertifikat.

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

Mengontrol dampak performa Always Encrypted

Karena Always Encrypted adalah teknologi enkripsi sisi klien, sebagian besar overhead performa diamati di sisi klien, bukan dalam database. Terlepas dari biaya operasi enkripsi dan dekripsi, sumber kinerja overhead lainnya di sisi klien adalah:

  • Perjalanan pulang pergi ekstra ke database untuk mengambil metadata untuk parameter kueri.
  • Memanggil ke penyimpanan kunci master kolom untuk mengakses kunci master kolom.

Bagian ini menjelaskan pengoptimalan performa bawaan di Microsoft .NET Data Provider untuk SQL Server dan bagaimana Anda dapat mengontrol dampak dari dua faktor di atas pada performa.

Mengontrol perjalanan pulang pergi untuk mengambil metadata untuk parameter kueri

Jika Always Encrypted diaktifkan untuk koneksi, secara default, Penyedia Data .NET Microsoft untuk SQL Server akan memanggil sys.sp_describe_parameter_encryption untuk setiap kueri berparameter, meneruskan pernyataan kueri (tanpa nilai parameter apa pun) ke SQL Server. sys.sp_describe_parameter_encryption menganalisis pernyataan kueri untuk mengetahui apakah ada parameter yang perlu dienkripsi, dan jika demikian, untuk masing-masing parameter, ia mengembalikan informasi terkait enkripsi yang akan memungkinkan Penyedia Data .NET Microsoft untuk SQL Server mengenkripsi nilai parameter. Perilaku di atas memastikan tingkat transparansi yang tinggi terhadap aplikasi klien. Aplikasi (dan pengembang aplikasi) tidak perlu mengetahui kueri mana yang mengakses kolom terenkripsi, selama nilai yang menargetkan kolom terenkripsi diteruskan ke Penyedia Data Microsoft .NET untuk SQL Server di objek SqlParameter.

Penembolokan metadata kueri

Penyedia Data Microsoft .NET untuk SQL Server menyimpan hasil sys.sp_describe_parameter_encryption untuk setiap pernyataan kueri. Jadi, jika pernyataan kueri yang sama dijalankan beberapa kali, driver memanggil sys.sp_describe_parameter_encryption hanya sekali. Penembolokan metadata enkripsi untuk pernyataan kueri secara substansial mengurangi biaya performa pengambilan metadata dari database. Penembolokan diaktifkan secara default. Anda dapat menonaktifkan penembolokan metadata parameter dengan mengatur Sql Koneksi ion. Properti ColumnEncryptionQueryMetadataCacheEnabled ke false, tetapi melakukannya tidak disarankan kecuali dalam kasus yang jarang terjadi seperti yang dijelaskan di bawah ini:

Pertimbangkan database yang memiliki dua skema berbeda: s1 dan s2. Setiap skema berisi tabel dengan nama yang sama: t. Definisi s1.t tabel dan s2.t identik, kecuali properti terkait enkripsi: Kolom, bernama c, tidak dienkripsi, dan dienkripsi s1.t di s2.t. Database memiliki dua pengguna: u1 dan u2. Skema default untuk u1 pengguna adalah s1. Skema default untuk u2 adalah s2. Aplikasi .NET membuka dua koneksi ke database, meniru u1 pengguna pada satu koneksi, dan u2 pengguna pada koneksi lain. Aplikasi mengirim kueri dengan parameter yang menargetkan c kolom melalui koneksi untuk pengguna u1 (kueri tidak menentukan skema, sehingga skema pengguna default diasumsikan). Selanjutnya, aplikasi mengirimkan kueri yang sama melalui koneksi untuk u2 pengguna. Jika penembolokan metadata kueri diaktifkan, setelah kueri pertama, cache akan diisi dengan metadata yang menunjukkan c kolom, yang ditargetkan parameter kueri, tidak dienkripsi. Karena kueri kedua memiliki pernyataan kueri yang identik, informasi yang disimpan dalam cache akan digunakan. Akibatnya, driver akan mengirim kueri tanpa mengenkripsi parameter (yang salah, karena kolom target, s2.t.c, dienkripsi), membocorkan nilai teks biasa parameter ke server. Server akan mendeteksi ketidaksesuaian itu dan akan memaksa driver untuk menyegarkan cache, sehingga aplikasi akan secara transparan mengirim ulang kueri dengan nilai parameter yang dienkripsi dengan benar. Dalam kasus seperti itu, penembolokan harus dinonaktifkan untuk mencegah kebocoran nilai sensitif ke server.

Mengatur Always Encrypted pada tingkat kueri

Untuk mengontrol dampak performa pengambilan metadata enkripsi untuk kueri berparameter, Anda dapat mengaktifkan Always Encrypted untuk kueri individual, alih-alih menyiapkannya untuk koneksi. Dengan cara ini, Anda dapat memastikan bahwa sys.sp_describe_parameter_encryption hanya dipanggil untuk kueri yang Anda ketahui memiliki parameter yang menargetkan kolom terenkripsi. Namun, perhatikan bahwa dengan melakukannya, Anda mengurangi transparansi enkripsi: jika Anda mengubah properti enkripsi kolom database, Anda mungkin perlu mengubah kode aplikasi Anda untuk menyelaraskannya dengan perubahan skema.

Catatan

Pengaturan Always Encrypted pada tingkat kueri membatasi manfaat performa penembolokan metadata enkripsi parameter.

Untuk mengontrol perilaku Always Encrypted dari masing-masing kueri, Anda perlu menggunakan konstruktor SqlCommand dan SqlCommandColumnEncryptionSetting ini. Berikut adalah beberapa panduan yang berguna:

  • Jika sebagian besar kueri aplikasi klien menjalankan kolom terenkripsi akses:
    • Atur Pengaturan Enkripsi Kolom string koneksi kata kunci ke Diaktifkan.
    • Atur SqlCommandColumnEncryptionSetting ke Dinonaktifkan untuk kueri individual yang tidak mengakses kolom terenkripsi apa pun. Pengaturan ini akan menonaktifkan panggilan sys.sp_describe_parameter_encryption dan upaya untuk mendekripsi nilai apa pun dalam tataan hasil.
    • Atur SqlCommandColumnEncryptionSetting ke ResultSetOnly untuk kueri individual yang tidak memiliki parameter apa pun yang memerlukan enkripsi, tetapi ambil data dari kolom terenkripsi. Pengaturan ini akan menonaktifkan panggilan sys.sp_describe_parameter_encryption dan enkripsi parameter. Kueri akan dapat mendekripsi hasil dari kolom enkripsi.
  • Jika sebagian besar kueri yang dijalankan aplikasi klien tidak mengakses kolom terenkripsi:
    • Atur Pengaturan Enkripsi Kolom string koneksi kata kunci ke Dinonaktifkan.
    • Atur SqlCommandColumnEncryptionSetting ke Diaktifkan untuk kueri individual yang memiliki parameter apa pun yang perlu dienkripsi. Pengaturan ini akan memungkinkan panggilan sys.sp_describe_parameter_encryption dan dekripsi hasil kueri apa pun yang diambil dari kolom terenkripsi.
    • Atur SqlCommandColumnEncryptionSetting ke ResultSetOnly untuk kueri yang tidak memiliki parameter apa pun yang memerlukan enkripsi, tetapi mengambil data dari kolom terenkripsi. Pengaturan ini akan menonaktifkan panggilan sys.sp_describe_parameter_encryption dan enkripsi parameter. Kueri akan dapat mendekripsi hasil dari kolom enkripsi.

Dalam contoh di bawah ini, Always Encrypted dinonaktifkan untuk koneksi database. Kueri masalah aplikasi memiliki parameter yang menargetkan kolom LastName yang tidak dienkripsi. Kueri mengambil data dari SSN kolom dan BirthDate yang keduanya dienkripsi. Dalam kasus seperti itu, memanggil sys.sp_describe_parameter_encryption untuk mengambil metadata enkripsi tidak diperlukan. Namun, dekripsi hasil kueri perlu diaktifkan, sehingga aplikasi dapat menerima nilai teks biasa dari dua kolom terenkripsi. Pengaturan SqlCommandColumnEncryptionSettingResultSetOnly digunakan untuk memastikannya.

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

Penembolokan kunci enkripsi kolom

Untuk mengurangi jumlah panggilan ke penyimpanan kunci master kolom untuk mendekripsi kunci enkripsi kolom, Penyedia Data Microsoft .NET untuk SQL Server menyimpan kunci enkripsi kolom teks biasa dalam memori. Setelah penyedia menerima nilai kunci enkripsi kolom terenkripsi dari metadata database, driver pertama-tama mencoba menemukan kunci enkripsi kolom teks biasa yang sesuai dengan nilai kunci terenkripsi. Driver memanggil penyimpanan kunci yang berisi kunci master kolom hanya jika tidak dapat menemukan nilai kunci enkripsi kolom terenkripsi di cache.

Entri cache dikeluarkan setelah interval time-to-live yang dapat dikonfigurasi karena alasan keamanan. Nilai time-to-live default adalah 2 jam. Jika Anda memiliki persyaratan keamanan yang lebih ketat tentang berapa lama kunci enkripsi kolom dapat di-cache dalam teks biasa dalam aplikasi, Anda dapat mengubahnya menggunakan Sql Koneksi ion. Properti ColumnEncryptionKeyCacheTtl.

Penyedia penyimpanan kunci kustom terdaftar menggunakan Sql Koneksi ion. RegisterColumnEncryptionKeyStoreProvidersOn Koneksi ion dan SqlCommand.RegisterColumnEncryptionKeyStoreProvidersOnCommand tidak akan memiliki kunci enkripsi kolom yang didekripsi yang di-cache oleh Penyedia Data Microsoft .NET untuk SQL Server. Sebagai gantinya, penyedia penyimpanan kunci kustom harus menerapkan mekanisme penembolokan mereka sendiri. Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProviderv3.0.0 dan yang lebih tinggi dilengkapi dengan implementasi penembolokannya sendiri.

Untuk mendukung skenario di mana pengguna yang berbeda dari aplikasi yang sama dapat menjalankan beberapa kueri, penyedia penyimpanan kunci kustom dapat dipetakan ke pengguna dan terdaftar pada koneksi atau instans perintah khusus untuk pengguna tersebut. Contoh berikut menunjukkan bagaimana instans Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider dapat digunakan kembali di berbagai SqlCommand objek untuk pengguna yang sama. Cache kunci enkripsi kolomnya akan bertahan di beberapa kueri, mengurangi jumlah perjalanan pulang pergi ke penyimpanan kunci:

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

Mengaktifkan perlindungan ekstra untuk SQL Server yang disusupi

Secara default, Penyedia Data Microsoft .NET untuk SQL Server bergantung pada sistem database (SQL Server atau Azure SQL Database) untuk menyediakan metadata tentang kolom mana dalam database yang dienkripsi dan bagaimana. Metadata enkripsi memungkinkan Penyedia Data .NET Microsoft untuk SQL Server mengenkripsi parameter kueri dan mendekripsi hasil kueri tanpa input apa pun dari aplikasi, yang sangat mengurangi jumlah perubahan yang diperlukan dalam aplikasi. Namun, jika proses SQL Server disusupi dan penyerang merusak metadata yang dikirim SQL Server ke Penyedia Data Microsoft .NET untuk SQL Server, penyerang mungkin dapat mencuri informasi sensitif. Bagian ini menjelaskan API yang membantu memberikan tingkat perlindungan ekstra terhadap jenis serangan ini, dengan harga transparansi yang berkurang.

Memaksa Enkripsi Parameter

Sebelum Penyedia Data .NET Microsoft untuk SQL Server mengirim kueri berparameter ke SQL Server, ia meminta SQL Server (dengan memanggil sys.sp_describe_parameter_encryption) untuk menganalisis pernyataan kueri dan memberikan informasi tentang parameter mana dalam kueri yang harus dienkripsi. Instans SQL Server yang disusupi dapat menyesatkan Penyedia Data Microsoft .NET untuk SQL Server dengan mengirim metadata yang menunjukkan parameter tidak menargetkan kolom terenkripsi, meskipun kolom dienkripsi dalam database. Akibatnya, Penyedia Data Microsoft .NET untuk SQL Server tidak akan mengenkripsi nilai parameter, dan akan mengirimkannya sebagai teks biasa ke instans SQL Server yang disusupi.

Untuk mencegah serangan seperti itu , aplikasi dapat mengatur Properti SqlParameter.ForceColumnEncryption untuk parameter ke true. Pengaturan ini akan menyebabkan Penyedia Data .NET Microsoft untuk SQL Server melemparkan pengecualian, jika metadata yang diterimanya dari server menunjukkan parameter tidak perlu dienkripsi.

Meskipun menggunakan properti SqlParameter.ForceColumnEncryption membantu meningkatkan keamanan, properti ini juga mengurangi transparansi enkripsi ke aplikasi klien. Jika Anda memperbarui skema database untuk mengubah kumpulan kolom terenkripsi, Anda mungkin juga perlu membuat perubahan aplikasi.

Sampel kode berikut mengilustrasikan menggunakan properti SqlParameter.ForceColumnEncryption untuk mencegah nomor jaminan sosial dikirim dalam teks biasa ke database.

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

Mengonfigurasi jalur kunci master kolom tepercaya

Metadata enkripsi SQL Server ditampilkan untuk parameter kueri yang menargetkan kolom terenkripsi dan untuk hasil yang diambil dari kolom enkripsi mencakup jalur kunci kunci master kolom yang mengidentifikasi penyimpanan kunci dan lokasi kunci di penyimpanan kunci. Jika instans SQL Server disusupi, instans tersebut dapat mengirim jalur kunci yang mengarahkan Penyedia Data Microsoft .NET untuk SQL Server ke lokasi yang dikendalikan oleh penyerang. Proses ini dapat menyebabkan bocornya kredensial penyimpanan kunci, jika penyimpanan kunci mengharuskan aplikasi untuk mengautentikasi.

Untuk mencegah serangan tersebut, aplikasi dapat menentukan daftar jalur kunci tepercaya untuk server tertentu menggunakan Sql Koneksi ion. Properti ColumnEncryptionTrustedMasterKeyPaths. Jika Penyedia Data .NET Microsoft untuk SQL Server menerima jalur kunci di luar daftar jalur kunci tepercaya, itu akan melemparkan pengecualian.

Meskipun mengatur jalur kunci tepercaya meningkatkan keamanan aplikasi, Anda harus mengubah kode atau/dan konfigurasi aplikasi setiap kali Anda memutar kunci master kolom (setiap kali jalur kunci master kolom berubah).

Contoh berikut menunjukkan cara mengonfigurasi jalur kunci master kolom tepercaya:

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

Menyalin data terenkripsi menggunakan SqlBulkCopy

Dengan SqlBulkCopy, Anda dapat menyalin data, yang sudah dienkripsi dan disimpan dalam satu tabel, ke tabel lain, tanpa mendekripsi data. Untuk melakukannya:

  • Pastikan konfigurasi enkripsi tabel target identik dengan konfigurasi tabel sumber. Secara khusus, kedua tabel harus memiliki kolom yang sama yang dienkripsi, dan kolom harus dienkripsi menggunakan jenis enkripsi yang sama dan kunci enkripsi yang sama. Jika salah satu kolom target dienkripsi secara berbeda dari kolom sumber yang sesuai, Anda tidak akan dapat mendekripsi data dalam tabel target setelah operasi salin. Data akan rusak.
  • Konfigurasikan kedua koneksi database ke tabel sumber dan ke tabel target tanpa Always Encrypted diaktifkan.
  • Atur AllowEncryptedValueModifications opsi (lihat SqlBulkCopyOptions).

Catatan

Berhati-hatilah saat menentukan AllowEncryptedValueModifications. Pengaturan ini dapat menyebabkan kerusakan database karena Penyedia Data .NET Microsoft untuk SQL Server tidak memeriksa apakah data memang dienkripsi, atau apakah data dienkripsi dengan benar menggunakan jenis enkripsi, algoritma, dan kunci yang sama dengan kolom target.

Berikut adalah contoh yang menyalin data dari satu tabel ke tabel lainnya. Kolom SSN dan BirthDate diasumsikan untuk dienkripsi.

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

referensi API Always Encrypted

Namespace:Microsoft.Data.SqlClient

Assembly: Microsoft.Data.SqlClient.dll

Nama Deskripsi
Kelas SqlColumnEncryptionCertificateStoreProvider Penyedia penyimpanan kunci untuk Penyimpanan Sertifikat Windows.
Kelas SqlColumnEncryptionCngProvider Penyedia penyimpanan kunci untuk Microsoft Cryptography API: Next Generation (CNG).
Kelas SqlColumnEncryptionCspProvider Penyedia penyimpanan kunci untuk Penyedia Layanan Kriptografi (CSP) berbasis Microsoft CAPI.
Kelas SqlColumnEncryptionKeyStoreProvider Kelas dasar penyedia penyimpanan kunci.
Enumerasi SqlCommandColumnEncryptionSetting Pengaturan untuk mengontrol perilaku Always Encrypted untuk kueri individual.
Enumerasi Sql Koneksi ionAttestationProtocol Menentukan nilai untuk Protokol Pengesahan saat menggunakan Always Encrypted dengan enklave aman
Enumerasi Sql Koneksi ionColumnEncryptionSetting Pengaturan untuk mengaktifkan enkripsi dan dekripsi untuk koneksi database.
Properti Sql Koneksi ionStringBuilder.ColumnEncryptionSetting Mendapatkan dan mengatur Always Encrypted di string koneksi.
Sql Koneksi ion. Properti ColumnEncryptionQueryMetadataCacheEnabled Mengaktifkan dan menonaktifkan penembolokan metadata kueri enkripsi.
Sql Koneksi ion. Properti ColumnEncryptionKeyCacheTtl Mendapatkan dan mengatur time-to-live untuk entri dalam cache kunci enkripsi kolom.
Sql Koneksi ion. Properti ColumnEncryptionTrustedMasterKeyPaths Memungkinkan Anda mengatur daftar jalur kunci tepercaya untuk server database. Jika saat memproses kueri aplikasi, driver menerima jalur kunci yang tidak ada dalam daftar, kueri akan gagal. Properti ini memberikan perlindungan ekstra terhadap serangan keamanan yang melibatkan SQL Server yang disusupi yang menyediakan jalur kunci palsu, yang dapat menyebabkan kebocoran kredensial penyimpanan kunci.
Sql Koneksi ion. Metode RegisterColumnEncryptionKeyStoreProviders Memungkinkan Anda mendaftarkan penyedia penyimpanan kunci kustom. Ini adalah kamus yang memetakan nama penyedia penyimpanan kunci ke implementasi penyedia penyimpanan kunci.
Konstruktor SqlCommand (String, Sql Koneksi ion, SqlTransaction, SqlCommandColumnEncryptionSetting) Memungkinkan Anda mengontrol perilaku Always Encrypted untuk kueri individual.
Properti SqlParameter.ForceColumnEncryption Memberlakukan enkripsi parameter. Jika SQL Server memberi tahu driver bahwa parameter tidak perlu dienkripsi, kueri yang menggunakan parameter akan gagal. Properti ini memberikan perlindungan ekstra terhadap serangan keamanan yang melibatkan SQL Server yang disusupi yang memberikan metadata enkripsi yang salah kepada klien, yang dapat menyebabkan pengungkapan data.
kata kunci string koneksi:Column Encryption Setting=enabled Mengaktifkan atau menonaktifkan fungsionalitas Always Encrypted untuk koneksi.

Lihat juga