Menggunakan Always Encrypted dengan Driver ODBC untuk SQL Server

Unduh driver ODBC

Berlaku untuk

  • Odbc Driver 13.1+ untuk SQL Server

Pendahuluan

Artikel ini memberikan informasi tentang cara mengembangkan aplikasi ODBC dengan menggunakan Always Encrypted (Mesin Database) atau Always Encrypted dengan enklave aman serta Driver ODBC 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 Driver ODBC untuk SQL Server, mencapai keamanan ini dengan mengenkripsi dan mendekripsi data sensitif secara transparan dalam 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 SQL Server atau Azure SQL Database. Demikian pula, driver secara transparan mendekripsi data yang diambil dari kolom database terenkripsi dalam hasil kueri. Always Encrypted dengan enklave aman memperluas kemampuan fitur ini untuk memungkinkan fungsionalitas yang lebih kaya pada data sensitif, sembari menjaga kerahasiaan data.

Untuk informasi selengkapnya, lihat Always Encrypted (Database Engine) dan Always Encrypted with secure enclaves.

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. Secara khusus, database Anda harus berisi definisi metadata untuk Kunci Master Kolom (CMK), Kunci Enkripsi Kolom (CEK), dan tabel yang berisi satu atau beberapa kolom yang dienkripsi menggunakan CEK tersebut.

Jika Anda menggunakan Always Encrypted dengan enklave aman, lihat Mengembangkan aplikasi menggunakan Always Encrypted dengan enklave aman untuk prasyarat tambahan.

Mengaktifkan Always Encrypted dalam aplikasi ODBC

Cara term mudah untuk mengaktifkan enkripsi parameter dan dekripsi kolom terenkripsi resultset adalah dengan mengatur nilai ColumnEncryption kata kunci string koneksi ke Diaktifkan. Kode berikut adalah contoh string koneksi yang memungkinkan Always Encrypted:

SQLWCHAR *connString = L"Driver={ODBC Driver 18 for SQL Server};Server={myServer};Encrypt=yes;Trusted_Connection=yes;ColumnEncryption=Enabled;";

Always Encrypted juga dapat diaktifkan pada konfigurasi DSN, menggunakan kunci dan nilai yang sama (yang akan ditimpa oleh pengaturan string koneksi, jika ada), atau secara terprogram dengan atribut pra-koneksi SQL_COPT_SS_COLUMN_ENCRYPTION. Mengaturnya dengan cara ini mengambil alih nilai yang ditetapkan dalam string koneksi atau DSN:

 SQLSetConnectAttr(hdbc, SQL_COPT_SS_COLUMN_ENCRYPTION, (SQLPOINTER)SQL_COLUMN_ENCRYPTION_ENABLE, 0);

Setelah diaktifkan untuk koneksi, perilaku Always Encrypted dapat disesuaikan untuk kueri individual. Untuk informasi selengkapnya, lihat Mengontrol Dampak Performa Always Encrypted di bawah ini.

Mengaktifkan Always Encrypted tidak cukup untuk enkripsi atau dekripsi agar berhasil; Anda juga perlu memastikan bahwa:

  • Aplikasi ini memiliki izin basis data VIEW ANY COLUMN MASTER KEY DEFINITION dan VIEW ANY COLUMN ENCRYPTION KEY DEFINITION, yang diperlukan untuk mengakses metadata tentang kunci Always Encrypted di basis data. Untuk detail selengkapnya, lihat Izin Database.

  • Aplikasi dapat mengakses CMK yang melindungi CEK untuk kolom terenkripsi yang dikueri. Perilaku ini tergantung pada penyedia keystore yang menyimpan CMK. Untuk informasi selengkapnya, lihat Bekerja dengan Penyimpanan Kunci Master Kolom.

Mengaktifkan Always Encrypted dengan enklave aman

Catatan

Pada Linux dan macOS, OpenSSL versi 1.0.1 atau yang lebih baru diperlukan untuk menggunakan Always Encrypted dengan enklave aman.

Mulai versi 17.4, driver mendukung Always Encrypted dengan enklave aman. Untuk mengaktifkan penggunaan enklave saat menyambungkan ke database, atur ColumnEncryption kunci DSN, kata kunci string koneksi, atau atribut koneksi ke nilai berikut: <attestation protocol>,<attestation URL>, di mana:

  • <attestation protocol> - menentukan protokol yang digunakan untuk pengesahan enklave.

    • Jika Anda menggunakan SQL Server dan Host Guardian Service (HGS), maka <attestation protocol> harus VBS-HGS.
    • Jika Anda menggunakan Azure SQL Database dan Microsoft Azure Attestation, <attestation protocol> harus SGX-AAS.
    • Jika Anda tidak memerlukan pengesahan, <attestation-protocol> harus VBS-NONE. (Versi 18.1+)
  • <attestation URL> - menentukan URL pengesahan (titik akhir layanan pengesahan). Anda perlu mendapatkan URL pengesahan untuk lingkungan Anda dari administrator layanan pengesahan Anda.

    • Jika Anda menggunakan SQL Server dan Host Guardian Service (HGS), lihat Menentukan dan membagikan URL pengesahan HGS.
    • Jika Anda menggunakan Azure SQL Database dan Microsoft Azure Attestation, lihat Menentukan URL pengesahan untuk kebijakan pengesahan Anda.
    • Jika Anda tidak memerlukan pengesahan, jangan tentukan URL pengesahan (atau koma sebelumnya). (Versi 18.1+)

Contoh string koneksi yang mengaktifkan komputasi enklave untuk koneksi database:

  • SQL Server:

    "Driver=ODBC Driver 18 for SQL Server;Server=myServer.myDomain;Encrypt=yes;Database=myDataBase;Trusted_Connection=Yes;ColumnEncryption=VBS-HGS,http://myHGSServer.myDomain/Attestation"
    
  • Azure SQL Database:

    "Driver=ODBC Driver 18 for SQL Server;Server=myServer.database.windows.net;Database=myDataBase;Uid=myUsername;Pwd=<password>;Encrypt=yes;ColumnEncryption=SGX-AAS,https://myAttestationProvider.uks.attest.azure.net/"
    
  • Tidak ada pengesahan (v18.1+):

    "Driver=ODBC Driver 18 for SQL Server;Server=myServer.database.windows.net;Database=myDataBase;Uid=myUsername;Pwd=<password>;Encrypt=yes;ColumnEncryption=VBS-NONE"
    

Jika server dan layanan pengesahan dikonfigurasi dengan benar, bersama CMK dan CEK yang mendukung enklave untuk kolom yang dienkripsi, Anda dapat menjalankan kueri yang menggunakan enklave, seperti enkripsi langsung di tempat dan komputasi tingkat lanjut, selain fungsionalitas yang sudah disediakan oleh Always Encrypted. Untuk informasi selengkapnya, lihat Mengonfigurasi Always Encrypted dengan enklave aman.

Mengambil dan memodifikasi data dalam kolom terenkripsi

Setelah mengaktifkan Always Encrypted pada koneksi, Anda dapat menggunakan API ODBC standar. API ODBC dapat mengambil atau memodifikasi data dalam kolom database terenkripsi. Item dokumentasi berikut mungkin berguna:

Aplikasi Anda harus memiliki izin database yang diperlukan, dan harus dapat mengakses kunci master kolom. Kemudian driver mengenkripsi parameter kueri apa pun yang menargetkan kolom terenkripsi. Driver juga mendekripsi data yang diambil dari kolom terenkripsi. Driver melakukan semua enkripsi dan dekripsi ini tanpa bantuan dari kode sumber Anda. Bagi program Anda, seolah-olah kolom-kolom tersebut tidak dienkripsi.

Jika Always Encrypted tidak diaktifkan, kueri dengan parameter yang menargetkan kolom terenkripsi akan gagal. Data masih dapat diambil dari kolom terenkripsi, selama kueri tidak memiliki parameter yang menargetkan kolom terenkripsi. Namun, driver tidak akan mencoba dekripsi apa pun dan aplikasi akan menerima data terenkripsi biner (sebagai array byte).

Tabel di bawah ini meringkas perilaku kueri, tergantung 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
Parameter yang menargetkan kolom terenkripsi. Nilai parameter dienkripsi secara transparan. Kesalahan Kesalahan
Mengambil data dari kolom terenkripsi, tanpa parameter yang menargetkan kolom terenkripsi. Hasil dari kolom terenkripsi didekripsi secara transparan. Aplikasi menerima nilai kolom teks biasa. Kesalahan Hasil dari kolom terenkripsi tidak didekripsi. Aplikasi menerima nilai terenkripsi dalam bentuk larik byte.

Contoh berikut mengilustrasikan pengambilan dan modifikasi data dalam kolom terenkripsi. Contoh mengasumsikan tabel dengan skema berikut. 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

Contoh penyisipan data

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

  • Tidak ada yang khusus untuk enkripsi dalam kode sampel. Driver secara otomatis mendeteksi dan mengenkripsi nilai parameter SSN dan tanggal, yang menargetkan kolom terenkripsi. Perilaku ini membuat enkripsi transparan ke aplikasi.

  • Nilai yang disisipkan ke dalam kolom database, termasuk kolom terenkripsi, diteruskan sebagai parameter terikat (lihat Fungsi SQLBindParameter). Meskipun penggunaan parameter bersifat opsional saat mengirim nilai ke kolom yang tidak dienkripsi (meskipun sangat disarankan karena membantu mencegah injeksi SQL), parameter wajib digunakan untuk nilai yang ditujukan ke kolom terenkripsi. Jika nilai yang dimasukkan ke dalam kolom SSN atau BirthDate dikirimkan sebagai nilai literal yang disisipkan langsung dalam pernyataan kueri, kueri akan gagal karena driver tidak mencoba mengenkripsi atau memproses nilai literal dalam kueri. Akibatnya, server akan menolaknya sebagai tidak kompatibel dengan kolom terenkripsi.

  • Tipe SQL dari parameter yang disisipkan ke kolom SSN diatur ke SQL_CHAR, yang dipetakan ke tipe data SQL Server char (rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 11, 0, (SQLPOINTER)SSN, 0, &cbSSN);). Jika jenis parameter diatur ke SQL_WCHAR, yang memetakan ke nchar, kueri akan gagal, karena Always Encrypted tidak mendukung konversi sisi server dari nilai nchar terenkripsi ke nilai karakter terenkripsi. Lihat Referensi Pemrogram ODBC -- Lampiran D: Tipe Data untuk informasi mengenai pemetaan tipe data.

    SQL_DATE_STRUCT date;
    SQLLEN cbdate;   // size of date structure  

    SQLCHAR SSN[12];
    strcpy_s((char*)SSN, _countof(SSN), "795-73-9838");

    SQLWCHAR* firstName = L"Catherine";
    SQLWCHAR* lastName = L"Abel";
    SQLINTEGER cbSSN = SQL_NTS, cbFirstName = SQL_NTS, cbLastName = SQL_NTS;

    // Initialize the date structure  
    date.day = 10;
    date.month = 9;
    date.year = 1996;

    // Size of structures   
    cbdate = sizeof(SQL_DATE_STRUCT);

    SQLRETURN rc = 0;

    string queryText = "INSERT INTO [dbo].[Patients] ([SSN], [FirstName], [LastName], [BirthDate]) VALUES (?, ?, ?, ?) ";

    rc = SQLPrepare(hstmt, (SQLCHAR *)queryText.c_str(), SQL_NTS);

    //SSN
    rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 11, 0, (SQLPOINTER)SSN, 0, &cbSSN);
    //FirstName
    rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_WCHAR, 50, 0, (SQLPOINTER)firstName, 0, &cbFirstName);
    //LastName
    rc = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_WCHAR, 50, 0, (SQLPOINTER)lastName, 0, &cbLastName);
    //BirthDate
    rc = SQLBindParameter(hstmt, 4, SQL_PARAM_INPUT, SQL_C_TYPE_DATE, SQL_TYPE_DATE, 10, 0, (SQLPOINTER)&date, 0, &cbdate);

    rc = SQLExecute(hstmt);

Contoh pengambilan data teks biasa

Contoh berikut menunjukkan pemfilteran data berdasarkan nilai terenkripsi, dan mengambil data teks biasa dari kolom terenkripsi. Perhatikan detail berikut:

  • Nilai yang digunakan dalam klausul WHERE untuk memfilter pada kolom SSN perlu diteruskan menggunakan SQLBindParameter, sehingga driver dapat mengenkripsinya secara transparan sebelum mengirimkannya ke server.

  • Semua nilai yang dicetak oleh program akan berada dalam teks biasa, karena driver akan secara transparan mendekripsi data yang diambil dari kolom SSN dan BirthDate.

Catatan

Kueri dapat melakukan perbandingan kesetaraan pada kolom terenkripsi hanya jika enkripsi deterministik, atau jika enklave aman diaktifkan.

SQLCHAR SSN[12];
strcpy_s((char*)SSN, _countof(SSN), "795-73-9838");

SQLWCHAR* firstName = L"Catherine";
SQLWCHAR* lastName = L"Abel";
SQLINTEGER cbSSN = SQL_NTS, cbFirstName = SQL_NTS, cbLastName = SQL_NTS;

SQLRETURN rc = 0;
string empty = "";
string queryText = "SELECT [SSN], [FirstName], [LastName], [BirthDate] " + empty +
    "FROM  [dbo].[Patients]" +
    "WHERE " +
    "[SSN] = ? ";

rc = SQLPrepare(hstmt, (SQLCHAR *)queryText.c_str(), SQL_NTS);

//SSN
rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 11, 0, (SQLPOINTER)SSN, 0, &cbSSN);

rc = SQLExecute(hstmt);
HandleDiagnosticRecord(hstmt, SQL_HANDLE_STMT, rc);

SQL_DATE_STRUCT dateVal;
SQLWCHAR firstNameVal[50];
SQLWCHAR lastNameVal[50];
SQLCHAR SSNVal[12];
SQLLEN cbdate;   // size of date structure  

int rowcount = 0;
while (SQL_SUCCEEDED(SQLFetch(hstmt)))
{
    rowcount++;
    SQLGetData(hstmt, 1, SQL_C_CHAR, &SSNVal, 11, &cbSSN);
    SQLGetData(hstmt, 2, SQL_C_WCHAR, &firstNameVal, 50, &cbFirstName);
    SQLGetData(hstmt, 3, SQL_C_WCHAR, &lastNameVal, 50, &cbLastName);
    SQLGetData(hstmt, 4, SQL_C_TYPE_DATE, &dateVal, 10, &cbdate);        
}

Contoh pengambilan data Ciphertext

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

Contoh berikut mengilustrasikan pengambilan data terenkripsi biner dari kolom terenkripsi. Perhatikan detail berikut:

  • Karena Always Encrypted tidak diaktifkan dalam string koneksi, kueri akan mengembalikan nilai terenkripsi SSN dan BirthDate 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. Kueri di atas memfilter berdasarkan LastName, yang tidak dienkripsi di dalam basis data. Jika kueri difilter oleh SSN atau BirthDate, kueri akan gagal.
SQLCHAR SSN[12];
strcpy_s((char*)SSN, _countof(SSN), "795-73-9838");

SQLWCHAR* firstName = L"Catherine";
SQLWCHAR* lastName = L"Abel";
SQLINTEGER cbSSN = SQL_NTS, cbFirstName = SQL_NTS, cbLastName = SQL_NTS;

SQLRETURN rc = 0;
string empty = "";
string queryText = "SELECT [SSN], [FirstName], [LastName], [BirthDate] " + empty +
    "FROM  [dbo].[Patients]" +
    "WHERE " +
    "[LastName] = ?";

rc = SQLPrepare(hstmt, (SQLCHAR *)queryText.c_str(), SQL_NTS);

//LastName
rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_WCHAR, 50, 0, (SQLPOINTER)lastName, 0, &cbLastName);

rc = SQLExecute(hstmt);
HandleDiagnosticRecord(hstmt, SQL_HANDLE_STMT, rc);

SQL_DATE_STRUCT dateVal;
SQLWCHAR firstNameVal[50];
SQLWCHAR lastNameVal[50];
SQLCHAR SSNVal[12];
SQLLEN cbdate;   // size of date structure  

int rowcount = 0;
while (SQL_SUCCEEDED(SQLFetch(hstmt)))
{
    rowcount++;
    SQLGetData(hstmt, 1, SQL_C_CHAR, &SSNVal, 11, &cbSSN);
    SQLGetData(hstmt, 2, SQL_C_WCHAR, &firstNameVal, 50, &cbFirstName);
    SQLGetData(hstmt, 3, SQL_C_WCHAR, &lastNameVal, 50, &cbLastName);
    SQLGetData(hstmt, 4, SQL_C_TYPE_DATE, &dateVal, 10, &cbdate);        
}

Enkripsi Uang/SmallMoney

Mulai versi driver 17.7, Always Encrypted dapat digunakan dengan MONEY dan SMALLMONEY. Namun ada beberapa langkah tambahan yang harus diambil. Saat menyisipkan ke dalam kolom MONEY atau SMALLMONEY terenkripsi, gunakan salah satu jenis C berikut:

SQL_C_CHAR
SQL_C_WCHAR
SQL_C_SHORT
SQL_C_LONG
SQL_C_FLOAT
SQL_C_DOUBLE
SQL_C_BIT
SQL_C_TINYINT
SQL_C_SBIGINT
SQL_C_NUMERIC

dan jenis SQL berupa SQL_NUMERIC atau SQL_DOUBLE (presisi dapat hilang saat menggunakan jenis ini).

Mengikat variabel

Setiap kali mengikat variabel MONEY/SMALLMONEY di kolom terenkripsi, bidang deskriptor berikut harus diatur:

// n is the descriptor record of the MONEY/SMALLMONEY parameter
// the type is assumed to be SMALLMONEY if isSmallMoney is true and MONEY otherwise

SQLHANDLE ipd = 0;
SQLGetStmtAttr(hStmt, SQL_ATTR_IMP_PARAM_DESC, (SQLPOINTER)&ipd, SQL_IS_POINTER, NULL);
SQLSetDescField(ipd, n, SQL_CA_SS_SERVER_TYPE, isSmallMoney ? (SQLPOINTER)SQL_SS_TYPE_SMALLMONEY :
                                                              (SQLPOINTER)SQL_SS_TYPE_MONEY, SQL_IS_INTEGER);

// If the variable is bound as SQL_NUMERIC, additional descriptor fields have to be set
// var is SQL_NUMERIC_STRUCT containing the value to be inserted

SQLHDESC   hdesc = NULL;
SQLGetStmtAttr(hStmt, SQL_ATTR_APP_PARAM_DESC, &hdesc, 0, NULL);
SQLSetDescField(hdesc, n, SQL_DESC_PRECISION, (SQLPOINTER)(var.precision), 0);
SQLSetDescField(hdesc, n, SQL_DESC_SCALE, (SQLPOINTER)(var.scale), 0);
SQLSetDescField(hdesc, n, SQL_DESC_DATA_PTR, &var, 0);

Menghindari masalah umum saat mengkueri kolom terenkripsi

Bagian ini menjelaskan kategori kesalahan umum saat mengkueri kolom terenkripsi dari aplikasi ODBC 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 (Mesin Database) untuk daftar terperinci konversi jenis yang didukung. Untuk menghindari kesalahan konversi jenis data, pastikan Anda mengamati poin berikut saat menggunakan SQLBindParameter dengan parameter yang menargetkan kolom terenkripsi:

  • Jenis parameter SQL sama persis dengan jenis kolom yang ditargetkan, atau konversi dari jenis SQL ke jenis kolom didukung.

  • Presisi dan skala parameter yang menargetkan kolom dengan tipe data SQL Server decimal dan numeric sama dengan presisi dan skala yang dikonfigurasi untuk kolom target.

  • Presisi parameter yang menargetkan kolom dengan tipe data SQL Server datetime2, datetimeoffset, atau time tidak boleh lebih besar daripada presisi kolom target, pada kueri yang memodifikasi kolom target.

Kesalahan karena meneruskan teks biasa alih-alih nilai terenkripsi

Nilai apa pun yang menargetkan kolom terenkripsi perlu dienkripsi sebelum dikirim ke server. Upaya untuk menyisipkan, memodifikasi, atau memfilter berdasarkan nilai teks biasa pada kolom terenkripsi akan mengakibatkan kesalahan. Untuk mencegah kesalahan tersebut, pastikan bahwa:

  • Always Encrypted diaktifkan (di DSN, string koneksi, sebelum membuat koneksi dengan menetapkan atribut koneksi SQL_COPT_SS_COLUMN_ENCRYPTION untuk koneksi tertentu, atau atribut statement SQL_SOPT_SS_COLUMN_ENCRYPTION untuk statement tertentu).

  • Anda menggunakan SQLBindParameter untuk mengirim data yang menargetkan kolom terenkripsi. Contoh di bawah ini menunjukkan kueri yang secara keliru memfilter berdasarkan literal/konstanta pada kolom terenkripsi (SSN), alih-alih memberikan literal tersebut sebagai argumen ke SQLBindParameter.

string queryText = "SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE SSN='795-73-9838'";

Tindakan pencegahan saat menggunakan SQLSetPos dan SQLMoreResults

SQLSetPos

SQLSetPos API memungkinkan aplikasi memperbarui baris dalam kumpulan hasil menggunakan buffer yang dikaitkan dengan SQLBindCol dan yang sebelumnya telah diisi dengan data baris yang diambil. Karena perilaku padding asimetris pada tipe panjang tetap yang terenkripsi, data pada kolom-kolom ini dapat berubah tanpa diduga ketika memperbarui kolom lain dalam baris yang sama. Dengan AE, nilai karakter dengan panjang tetap akan diisi dengan karakter pengisi jika nilainya lebih kecil daripada ukuran buffer.

Untuk memitigasi perilaku ini, gunakan flag SQL_COLUMN_IGNORE untuk mengabaikan kolom yang tidak akan diperbarui sebagai bagian dari SQLBulkOperations serta saat menggunakan SQLSetPos untuk pembaruan berbasis kursor. Semua kolom yang tidak dimodifikasi langsung oleh aplikasi harus diabaikan, baik untuk performa maupun untuk menghindari pemotongan kolom yang terikat ke buffer yang lebih kecil dari ukuran sebenarnya (DB). Untuk informasi selengkapnya, lihat Referensi Fungsi SQLSetPos.

SQLMoreResults & SQLDescribeCol

Program aplikasi dapat memanggil SQLDescribeCol untuk mengembalikan metadata tentang kolom dalam pernyataan yang disiapkan. Saat Always Encrypted diaktifkan, panggilan SQLMoreResultssebelum memanggil SQLDescribeCol menyebabkan sp_describe_first_result_set dipanggil, yang tidak mengembalikan metadata teks biasa dengan benar untuk kolom terenkripsi. Untuk menghindari masalah ini, panggil SQLDescribeCol pada statemen yang disiapkan sebelum memanggil SQLMoreResults.

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.

  • Panggilan ke penyimpanan kunci utama kolom untuk mengakses kunci utama kolom.

Bagian ini menjelaskan pengoptimalan performa bawaan di Driver ODBC 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, driver akan, secara default, memanggil sys.sp_describe_parameter_encryption untuk setiap kueri berparameter, meneruskan pernyataan kueri (tanpa nilai parameter apa pun) ke SQL Server. Prosedur tersimpan ini menganalisis pernyataan kueri untuk mengetahui apakah ada parameter yang perlu dienkripsi, dan jika demikian, mengembalikan informasi terkait enkripsi untuk setiap parameter untuk memungkinkan driver mengenkripsinya. 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 driver dalam parameter.

Mulai versi 17.6, driver juga menyimpan metadata enkripsi untuk pernyataan yang disiapkan, meningkatkan performa dengan memungkinkan panggilan SQLExecute di masa mendatang untuk tidak memerlukan perjalanan pulang pergi tambahan untuk mengambil metadata enkripsi.

Perilaku Always Encrypted untuk setiap pernyataan

Untuk mengontrol dampak performa pengambilan metadata enkripsi untuk kueri berparameter, Anda dapat mengubah perilaku Always Encrypted untuk kueri individual jika telah diaktifkan pada 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 mengenkripsi lebih banyak kolom dalam database, Anda mungkin perlu mengubah kode aplikasi Anda untuk menyelaraskannya dengan perubahan skema.

Untuk mengontrol perilaku pernyataan Always Encrypted, panggil SQLSetStmtAttr untuk mengatur SQL_SOPT_SS_COLUMN_ENCRYPTION atribut pernyataan ke salah satu nilai berikut:

Nilai Deskripsi
SQL_CE_DISABLED (0) Always Encrypted dinonaktifkan untuk pernyataan
SQL_CE_RESULTSETONLY (1) Dekripsi saja. Tataan hasil dan nilai pengembalian didekripsi, dan parameter tidak dienkripsi
SQL_CE_ENABLED (3) Always Encrypted diaktifkan dan digunakan untuk parameter dan hasil

Handel pernyataan baru yang dibuat dari koneksi dengan Always Encrypted yang diaktifkan secara default diatur ke SQL_CE_ENABLED. Handel yang dibuat dari koneksi dengan fitur tersebut dinonaktifkan secara default menjadi SQL_CE_DISABLED (dan Always Encrypted tidak dapat diaktifkan pada handel tersebut.)

Jika sebagian besar kueri dari aplikasi klien mengakses kolom terenkripsi, hal-hal berikut disarankan:

  • Atur ColumnEncryption kata kunci string koneksi ke Enabled.

  • Atur atribut ke SQL_SOPT_SS_COLUMN_ENCRYPTIONSQL_CE_DISABLED pada pernyataan 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 atribut ke SQL_SOPT_SS_COLUMN_ENCRYPTIONSQL_CE_RESULTSETONLY pada pernyataan 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. Hasil yang berisi kolom terenkripsi akan terus didekripsi.

  • Gunakan prepared statement untuk kueri yang akan dijalankan lebih dari sekali; siapkan kueri dengan SQLPrepare dan simpan handle statement-nya, lalu gunakan kembali dengan SQLExecute setiap kali kueri tersebut dijalankan. Metode ini adalah pendekatan yang disukai untuk performa bahkan ketika tidak ada kolom terenkripsi, dan memungkinkan driver untuk memanfaatkan metadata yang di-cache.

Pengaturan keamanan Always Encrypted

Terapkan enkripsi kolom

Untuk menerapkan enkripsi parameter, atur SQL_CA_SS_FORCE_ENCRYPT bidang deskriptor parameter implementasi (IPD) melalui panggilan ke fungsi SQLSetDescField. Nilai bukan nol menyebabkan driver mengembalikan kesalahan ketika tidak ada metadata enkripsi yang dikembalikan untuk parameter terkait.

SQLHDESC ipd;
SQLGetStmtAttr(hStmt, SQL_ATTR_IMP_PARAM_DESC, &ipd, 0, 0);
SQLSetDescField(ipd, paramNum, SQL_CA_SS_FORCE_ENCRYPT, (SQLPOINTER)TRUE, SQL_IS_SMALLINT);   

Jika SQL Server memberi tahu driver bahwa parameter tidak perlu dienkripsi, kueri yang menggunakan parameter tersebut akan gagal. Perilaku ini memberikan perlindungan ekstra terhadap serangan keamanan yang melibatkan SQL Server yang disusupi yang menyediakan metadata enkripsi yang salah kepada klien, yang dapat menyebabkan pengungkapan data.

Cache kunci enkripsi kolom

Untuk mengurangi jumlah panggilan ke penyimpanan kunci utama kolom untuk mendekripsikan kunci enkripsi kolom, driver menyimpan CEK dalam bentuk teks biasa di memori. Cache CEK bersifat global untuk driver dan tidak terkait dengan satu koneksi. Setelah menerima ECEK dari metadata database, driver pertama-tama mencoba menemukan CEK teks biasa yang sesuai dengan nilai kunci terenkripsi dalam cache. Driver memanggil penyimpanan kunci yang berisi CMK hanya jika tidak dapat menemukan CEK teks biasa yang sesuai di cache.

Catatan

Di Driver ODBC untuk SQL Server, entri dalam cache dikeluarkan setelah batas waktu dua jam. Perilaku ini berarti bahwa untuk ECEK tertentu, driver menghubungi penyimpanan kunci hanya sekali selama masa pakai aplikasi atau setiap dua jam, mana yang kurang.

Dimulai dengan Driver ODBC 17.1 untuk SQL Server, batas waktu cache CEK dapat disesuaikan menggunakan SQL_COPT_SS_CEKCACHETTL atribut koneksi, yang menentukan jumlah detik CEK akan tetap berada di cache. Karena sifat global cache, atribut ini dapat disesuaikan dari handel koneksi apa pun yang valid untuk driver. Ketika TTL cache diturunkan, CEK yang ada yang akan melebihi TTL baru juga dikeluarkan. Jika nilainya 0, tidak ada CEK yang disimpan dalam cache.

Jalur kunci tepercaya

Mulai dari Driver ODBC 17.1 untuk SQL Server, atribut koneksi SQL_COPT_SS_TRUSTEDCMKPATHS memungkinkan aplikasi mewajibkan agar operasi Always Encrypted hanya menggunakan daftar CMK tertentu, yang diidentifikasi berdasarkan jalur kuncinya. Secara default, atribut ini adalah NULL, yang berarti bahwa driver menerima jalur kunci apa pun. Untuk menggunakan fitur ini, atur SQL_COPT_SS_TRUSTEDCMKPATHS agar menunjuk ke string karakter lebar yang dipisahkan oleh null dan diakhiri dengan null, yang mencantumkan satu atau beberapa jalur kunci yang diizinkan. Memori yang ditunjuk oleh atribut ini harus tetap valid selama operasi enkripsi atau dekripsi menggunakan handle koneksi yang padanya atribut ini ditetapkan --- setelah itu driver akan memeriksa apakah jalur CMK sebagaimana ditentukan oleh metadata server ada dalam daftar ini tanpa membedakan huruf besar/kecil. Jika jalur CMK tidak ada dalam daftar, operasi gagal. Aplikasi dapat mengubah konten memori tempat atribut ini menunjuk, untuk mengubah daftar CMK tepercayanya, tanpa mengatur atribut lagi.

Bekerja dengan penyimpanan kunci utama kolom

Untuk mengenkripsi atau mendekripsi data, driver perlu memperoleh CEK yang dikonfigurasi untuk kolom target. CEK disimpan dalam bentuk terenkripsi (ECEK) dalam metadata database. Setiap CEK memiliki CMK yang sesuai yang digunakan untuk mengenkripsinya. metadata database tidak menyimpan CMK itu sendiri; metadata database hanya berisi nama keystore dan informasi yang dapat digunakan oleh keystore untuk menemukan CMK.

Untuk mendapatkan nilai teks biasa dari ECEK, driver terlebih dahulu mendapatkan metadata tentang CEK dan CMK yang sesuai, lalu menggunakan informasi ini untuk menghubungi keystore yang berisi CMK dan memintanya untuk mendekripsi ECEK. Driver tersebut berkomunikasi dengan keystore melalui penyedia keystore.

Penyedia keystore bawaan

Driver ODBC untuk SQL Server dilengkapi dengan penyedia keystore bawaan berikut:

Nama Deskripsi Nama penyedia (metadata) Ketersediaan
Azure Key Vault Menyimpan CMK di Azure Key Vault AZURE_KEY_VAULT Windows, macOS, Linux
Penyimpanan Sertifikat Windows Menyimpan CMK secara lokal di keystore Windows MSSQL_CERTIFICATE_STORE Windows
  • Anda (atau DBA Anda) perlu memastikan bahwa nama penyedia, yang dikonfigurasi dalam metadata kunci master kolom, sudah benar dan jalur kunci master kolom mematuhi format jalur kunci 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 CREATE COLUMN MASTER KEY pernyataan (Transact-SQL).

  • Pastikan aplikasi Anda dapat mengakses kunci di keystore. Proses ini mungkin melibatkan pemberian akses aplikasi Anda ke kunci dan/atau keystore, tergantung pada keystore, atau melakukan langkah-langkah konfigurasi khusus keystore lainnya. Misalnya, untuk mengakses Azure Key Vault, Anda harus memberikan kredensial yang benar ke keystore.

Menggunakan penyedia Azure Key Vault

Azure Key Vault (AKV) adalah opsi mudah untuk menyimpan dan mengelola kunci master kolom untuk Always Encrypted (terutama jika aplikasi Anda dihosting di Azure). Driver ODBC untuk SQL Server di Linux, macOS, dan Windows menyertakan penyedia penyimpanan kunci master kolom bawaan untuk Azure Key Vault. Untuk informasi selengkapnya tentang mengonfigurasi Azure Key Vault untuk Always Encrypted, lihat Azure Key Vault - Langkah demi Langkah, Memulai Key Vault, dan Membuat Kunci Master Kolom di Azure Key Vault.

Catatan

Driver ODBC hanya mendukung autentikasi AKV secara langsung terhadap ID Microsoft Entra (sebelumnya Azure Active Directory). Jika Anda menggunakan autentikasi Microsoft Entra ke AKV dan konfigurasi Anda memerlukan autentikasi terhadap titik akhir Layanan Federasi Direktori Aktif, autentikasi mungkin gagal. Di Linux dan macOS, untuk driver versi 17.2 dan yang lebih baru, libcurl diperlukan untuk menggunakan penyedia ini, tetapi bukan dependensi eksplisit karena operasi lain dengan driver tidak memerlukannya. Jika Anda mengalami kesalahan mengenai libcurl, pastikan itu diinstal.

Driver mendukung autentikasi ke Azure Key Vault menggunakan jenis kredensial berikut:

  • Nama Pengguna/Kata Sandi - dengan metode ini, kredensial adalah nama pengguna Microsoft Entra dan kata sandinya.

  • ID Klien/Rahasia - dengan metode ini, kredensial adalah ID klien aplikasi dan rahasia aplikasi.

  • Identitas Terkelola (17.5.2+) - baik yang ditetapkan sistem maupun yang ditetapkan pengguna; untuk informasi selengkapnya, lihat Identitas Terkelola untuk sumber daya Azure.

  • Azure Key Vault Interactive (driver Windows 17.7+) - dengan metode ini, kredensial diautentikasi melalui Microsoft Entra ID dengan ID masuk.

Untuk mengizinkan driver menggunakan CMK yang disimpan di AKV untuk enkripsi kolom, gunakan kata kunci khusus string koneksi berikut:

Jenis Kredensial KeyStoreAuthentication KeyStorePrincipalId KeyStoreSecret
Nama pengguna/kata sandi KeyVaultPassword Nama Utama Pengguna Kata sandi
ID/rahasia klien KeyVaultClientSecret ID klien Rahasia
Identitas Terkelola KeyVaultManagedIdentity ID Objek (opsional, hanya untuk pengguna yang ditetapkan) (tidak ditentukan)
Interaktif AKV KeyVaultInteractive (tidak diatur) (tidak diatur)

Mulai dari v17.8, KeystoreAuthentication dan KeystorePrincipalId dapat diedit menggunakan UI konfigurasi DSN di Administrator Sumber Data ODBC.

Contoh rangkaian koneksi

String koneksi berikut menunjukkan cara mengautentikasi ke Azure Key Vault dengan dua jenis kredensial:

ClientID/Secret
"DRIVER=ODBC Driver 18 for SQL Server;SERVER=myServer;Encrypt=yes;Trusted_Connection=Yes;DATABASE=myDB;ColumnEncryption=Enabled;KeyStoreAuthentication=KeyVaultClientSecret;KeyStorePrincipalId=<clientId>;KeyStoreSecret=<secret>"
Nama Pengguna/Kata Sandi
"DRIVER=ODBC Driver 18 for SQL Server;SERVER=myServer;Encrypt=yes;Trusted_Connection=Yes;DATABASE=myDB;ColumnEncryption=Enabled;KeyStoreAuthentication=KeyVaultPassword;KeyStorePrincipalId=<username>;KeyStoreSecret=<password>"
Identitas Terkelola (yang ditetapkan sistem)
"DRIVER=ODBC Driver 18 for SQL Server;SERVER=myServer;Encrypt=yes;Trusted_Connection=Yes;DATABASE=myDB;ColumnEncryption=Enabled;KeyStoreAuthentication=KeyVaultManagedIdentity"
Identitas Terkelola (ditetapkan pengguna)
"DRIVER=ODBC Driver 18 for SQL Server;SERVER=myServer;Encrypt=yes;Trusted_Connection=Yes;DATABASE=myDB;ColumnEncryption=Enabled;KeyStoreAuthentication=KeyVaultManagedIdentity;KeyStorePrincipalId=<objectID>"
Interaktif AKV
"DRIVER=ODBC Driver 18 for SQL Server;SERVER=myServer;Encrypt=yes;Trusted_Connection=Yes;DATABASE=myDB;ColumnEncryption=Enabled;KeyStoreAuthentication=KeyVaultInteractive;UID=<userID>;PWD=<password>"

Tidak ada perubahan aplikasi ODBC lainnya yang diperlukan untuk menggunakan AKV untuk penyimpanan CMK.

Catatan

Driver berisi daftar endpoint AKV yang dipercaya. Mulai dari driver versi 17.5.2, daftar ini dapat dikonfigurasi: atur properti AKVTrustedEndpoints pada kunci registri ODBCINST.INI atau ODBC.INI milik driver atau DSN (Windows), atau pada bagian file odbcinst.ini atau odbc.ini (Linux/macOS), menjadi daftar yang dipisahkan dengan titik koma. Mengaturnya di DSN lebih diutamakan daripada pengaturan di driver. Jika nilai dimulai dengan titik koma, nilai akan memperluas daftar default; jika tidak, itu menggantikan daftar default. Daftar bawaan (pada versi 17.5) adalah vault.azure.net;vault.azure.cn;vault.usgovcloudapi.net;vault.microsoftazure.de. Mulai versi 17.7, daftar ini juga mencakup managedhsm.azure.net;managedhsm.azure.cn;managedhsm.usgovcloudapi.net;managedhsm.microsoftazure.de.

Catatan

Penyedia Azure Key Vault yang terintegrasi dalam driver ODBC mendukung baik Vault maupun Managed HSM di Azure Key Vault.

Menggunakan penyedia Windows Certificate Store

Driver ODBC untuk SQL Server di Windows menyertakan penyedia penyimpanan kunci master kolom bawaan untuk Windows Certificate Store, bernama MSSQL_CERTIFICATE_STORE. (Penyedia ini tidak tersedia di macOS atau Linux.) Dengan penyedia ini, CMK disimpan secara lokal di komputer klien dan tidak ada konfigurasi tambahan oleh aplikasi yang diperlukan untuk menggunakannya dengan driver. Namun, aplikasi harus memiliki akses ke sertifikat dan kunci privatnya di penyimpanan. Untuk informasi selengkapnya, lihat Membuat dan Menyimpan Kunci Master Kolom (Always Encrypted).

Menggunakan penyedia keystore kustom

Driver ODBC untuk SQL Server juga mendukung penyedia keystore pihak ketiga kustom menggunakan antarmuka CEKeystoreProvider. Fitur ini memungkinkan aplikasi memuat, mengkueri, dan mengonfigurasi penyedia keystore sehingga dapat digunakan oleh driver untuk mengakses kolom terenkripsi. Aplikasi juga dapat berinteraksi langsung dengan penyedia keystore untuk mengenkripsi CEK untuk penyimpanan di SQL Server dan melakukan tugas di luar mengakses kolom terenkripsi dengan ODBC; untuk informasi selengkapnya, lihat Penyedia Keystore Kustom.

Dua atribut koneksi digunakan untuk berinteraksi dengan penyedia keystore kustom. Yaitu:

  • SQL_COPT_SS_CEKEYSTOREPROVIDER

  • SQL_COPT_SS_CEKEYSTOREDATA

Yang pertama digunakan untuk memuat dan mencantumkan penyedia keystore yang telah dimuat, sedangkan yang terakhir memungkinkan komunikasi antara aplikasi dan penyedia. Atribut koneksi ini dapat digunakan kapan saja, sebelum atau sesudah membuat koneksi, karena interaksi penyedia aplikasi tidak melibatkan komunikasi dengan SQL Server. Namun, karena driver belum dimuat, mengatur dan mendapatkan atribut ini sebelum menyambungkan akan menyebabkannya diproses oleh Driver Manager, dan mungkin tidak menghasilkan hasil yang diharapkan.

Memuat penyedia keystore

Menetapkan atribut koneksi SQL_COPT_SS_CEKEYSTOREPROVIDER memungkinkan aplikasi klien memuat pustaka penyedia, sehingga penyedia keystore yang terdapat di dalamnya dapat digunakan.

SQLRETURN SQLSetConnectAttr( SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength);
Argumen Deskripsi
ConnectionHandle [Input] Handle koneksi. Harus berupa penangan koneksi yang valid, tetapi penyedia yang dimuat melalui satu penangan koneksi dapat diakses dari penangan koneksi lain mana pun di dalam proses yang sama.
Attribute [Input] Atribut yang akan diatur: konstanta SQL_COPT_SS_CEKEYSTOREPROVIDER .
ValuePtr [Input] Penunjuk ke string karakter yang diakhiri dengan null yang menentukan nama file pustaka penyedia. Untuk SQLSetConnectAttrA, nilai ini adalah string ANSI (multibyte). Untuk SQLSetConnectAttrW, nilai ini adalah string Unicode (wchar_t).
StringLength [Input] Panjang string ValuePtr, atau SQL_NTS.

Driver mencoba memuat pustaka yang diidentifikasi oleh parameter ValuePtr menggunakan mekanisme pemuatan pustaka dinamis yang ditentukan platform (dlopen() di Linux dan macOS, LoadLibrary() di Windows), dan menambahkan penyedia apa pun yang ditentukan di sana ke daftar penyedia yang diketahui oleh driver. Kesalahan berikut dapat terjadi:

Kesalahan Deskripsi
CE203 Pustaka dinamis tidak dapat dimuat.
CE203 Simbol "CEKeyStoreProvider" yang diekspor tidak ditemukan di pustaka.
CE203 Satu atau beberapa penyedia di pustaka sudah dimuat.

SQLSetConnectAttr mengembalikan nilai kesalahan atau keberhasilan yang biasa, dan informasi lebih lanjut tersedia untuk kesalahan apa pun yang terjadi melalui mekanisme diagnostik ODBC standar.

Catatan

Programmer aplikasi harus memastikan bahwa setiap penyedia kustom dimuat sebelum kueri yang mengharuskannya dikirim melalui koneksi apa pun. Kegagalan untuk melakukannya menghasilkan kesalahan:

Kesalahan Deskripsi
CE200 Penyedia keystore %1 tidak ditemukan. Pastikan bahwa pustaka penyedia keystore yang sesuai telah dimuat.

Catatan

Implementator penyedia keystore harus menghindari penggunaan MSSQL atas nama penyedia kustom mereka. Istilah ini dicadangkan secara eksklusif untuk penggunaan Microsoft dan dapat menyebabkan konflik dengan penyedia bawaan di masa mendatang. Menggunakan istilah ini atas nama penyedia kustom dapat mengakibatkan peringatan ODBC.

Mendapatkan daftar penyedia yang telah dimuat

Mendapatkan atribut koneksi ini memungkinkan aplikasi klien untuk menentukan penyedia keystore yang saat ini dimuat di driver (termasuk penyedia bawaan tersebut.) Proses ini hanya dapat dilakukan setelah menyambungkan.

SQLRETURN SQLGetConnectAttr( SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER BufferLength, SQLINTEGER * StringLengthPtr);
Argumen Deskripsi
ConnectionHandle [Input] Handle koneksi. Harus berupa penangan koneksi yang valid, tetapi penyedia yang dimuat melalui satu penangan koneksi dapat diakses dari penangan koneksi lain mana pun di dalam proses yang sama.
Attribute [Input] Atribut yang akan diambil: konstanta SQL_COPT_SS_CEKEYSTOREPROVIDER.
ValuePtr [Output] Pointer ke memori untuk mengembalikan nama penyedia yang dimuat berikutnya.
BufferLength [Input] Panjang ValuePtr buffer.
StringLengthPtr [Output] Penunjuk ke buffer untuk mengembalikan jumlah total byte (tidak termasuk karakter penghentian null) yang tersedia untuk dikembalikan dalam *ValuePtr. Jika ValuePtr adalah pointer null, tidak ada panjang yang dikembalikan. Jika nilai atribut adalah string dan jumlah byte yang tersedia untuk dikembalikan lebih besar daripada BufferLength dikurangi panjang karakter terminasi null, data dalam *ValuePtr dipotong menjadi BufferLength dikurangi panjang karakter terminasi null dan diakhiri dengan null oleh driver.

Untuk memungkinkan pengambilan seluruh daftar, setiap operasi Get mengembalikan nama penyedia saat ini dan menaikkan penghitung internal ke nilai berikutnya. Setelah penghitung ini mencapai akhir daftar, string kosong ("") dikembalikan, dan penghitung diatur ulang; operasi Get berikutnya kemudian berlanjut lagi dari awal daftar.

Berkomunikasi dengan penyedia keystore

Atribut koneksi SQL_COPT_SS_CEKEYSTOREDATA memungkinkan aplikasi klien berkomunikasi dengan penyedia keystore yang dimuat untuk mengonfigurasi parameter tambahan, materi kunci, dan sebagainya. Komunikasi antara aplikasi klien dan penyedia mengikuti protokol respons permintaan sederhana, berdasarkan permintaan Dapatkan dan Atur menggunakan atribut koneksi ini. Komunikasi hanya dimulai oleh aplikasi klien.

Catatan

Karena sifat panggilan ODBC yang ditangani oleh CEKeyStoreProvider (SQLGet/SetConnectAttr), antarmuka ODBC hanya mendukung penyetelan data pada tingkat konteks koneksi.

Aplikasi berkomunikasi dengan penyedia keystore melalui driver melalui struktur CEKeystoreData:

typedef struct CEKeystoreData {
wchar_t *name;
unsigned int dataSize;
char data[];
} CEKEYSTOREDATA;
Argumen Deskripsi
name [Input] Setelah Diatur, nama penyedia tempat data dikirim. Diabaikan pada Get. String karakter lebar yang diakhiri null.
dataSize [Input] Ukuran array data mengikuti struktur.
data [InOut] Setelah Diatur, data yang akan dikirim ke penyedia. Data ini mungkin bersifat acak; driver tidak berupaya menafsirkannya. Pada operasi Get, buffer untuk menerima data yang dibaca dari penyedia.

Menulis data ke penyedia

Panggilan SQLSetConnectAttr yang menggunakan atribut SQL_COPT_SS_CEKEYSTOREDATA menuliskan "paket" data ke penyedia keystore yang ditentukan.

SQLRETURN SQLSetConnectAttr( SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength);
Argumen Deskripsi
ConnectionHandle [Input] Handle koneksi. Harus berupa penangan koneksi yang valid, tetapi penyedia yang dimuat melalui satu penangan koneksi dapat diakses dari penangan koneksi lain mana pun di dalam proses yang sama.
Attribute [Input] Atribut yang akan diatur: konstanta SQL_COPT_SS_CEKEYSTOREDATA .
ValuePtr [Input] Pointer ke struktur CEKeystoreData. Bidang nama struktur mengidentifikasi penyedia tempat data dimaksudkan.
StringLength [Input] konstanta SQL_IS_POINTER

Informasi kesalahan yang lebih rinci dapat diperoleh melalui SQLGetDiacRec.

Catatan

Penyedia dapat menggunakan handle koneksi untuk mengaitkan data yang ditulis dengan koneksi tertentu, jika menginginkannya. Fitur ini berguna untuk menerapkan konfigurasi per koneksi. Ini juga dapat mengabaikan konteks koneksi dan memperlakukan data secara identik terlepas dari koneksi yang digunakan untuk mengirim data. Untuk informasi selengkapnya, lihat Asosiasi Konteks.

Membaca data dari penyedia

Pemanggilan SQLGetConnectAttr menggunakan atribut SQL_COPT_SS_CEKEYSTOREDATA membaca satu "paket" data dari penyedia yang terakhir ditulisi. Jika tidak ada, Kesalahan Urutan Fungsi terjadi. Pengimplementasi penyedia keystore didorong untuk mendukung "penulisan dummy" sebesar 0 byte sebagai cara untuk memilih penyedia bagi operasi pembacaan tanpa menimbulkan efek samping lain, jika hal itu masuk akal.

SQLRETURN SQLGetConnectAttr( SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER BufferLength, SQLINTEGER * StringLengthPtr);
Argumen Deskripsi
ConnectionHandle [Input] Handle koneksi. Harus berupa penangan koneksi yang valid, tetapi penyedia yang dimuat melalui satu penangan koneksi dapat diakses dari penangan koneksi lain mana pun di dalam proses yang sama.
Attribute [Input] Atribut yang akan diambil: konstanta SQL_COPT_SS_CEKEYSTOREDATA.
ValuePtr [Output] Penunjuk ke struktur CEKeystoreData tempat data yang dibaca dari penyedia ditempatkan.
BufferLength [Input] konstanta SQL_IS_POINTER
StringLengthPtr [Output] Pointer ke buffer tempat BufferLength akan dikembalikan. Jika *ValuePtr adalah penunjuk null, tidak ada panjang yang dikembalikan.

Pemanggil harus memastikan bahwa buffer dengan ukuran yang memadai setelah struktur CEKEYSTOREDATA dialokasikan agar penyedia dapat menulis ke dalamnya. Setelah kembali, bidang dataSize-nya diperbarui dengan panjang data aktual yang dibaca dari penyedia. Informasi kesalahan yang lebih rinci dapat diperoleh melalui SQLGetDiacRec.

Antarmuka ini tidak menempatkan persyaratan tambahan pada format data yang ditransfer antara aplikasi dan penyedia keystore. Setiap penyedia dapat menentukan protokol/format datanya sendiri, tergantung pada kebutuhannya.

Untuk contoh penerapan penyedia keystore Anda sendiri, lihat Penyedia Keystore Kustom

Batasan driver ODBC saat menggunakan Always Encrypted

Operasi Asinkron

Meskipun driver ODBC akan memungkinkan penggunaan operasi asinkron dengan Always Encrypted, ada dampak performa pada operasi ketika Always Encrypted diaktifkan. Panggilan ke sys.sp_describe_parameter_encryption untuk menentukan metadata enkripsi bagi pernyataan tersebut bersifat memblokir dan akan menyebabkan driver menunggu hingga server mengembalikan metadata sebelum mengembalikan SQL_STILL_EXECUTING.

Mengambil data dalam bagian dengan SQLGetData

Pada versi sebelum ODBC Driver 17 untuk SQL Server, kolom karakter dan biner terenkripsi tidak dapat diambil sebagian-sebagian dengan SQLGetData. Hanya satu panggilan ke SQLGetData yang dapat dilakukan, dengan buffer dengan panjang yang cukup untuk berisi seluruh data kolom.

Mengirim data dalam bagian dengan SQLPutData

Sebelum ODBC Driver 17.3 for SQL Server, data yang akan disisipkan atau dibandingkan tidak dapat dikirim secara bertahap dengan SQLPutData. Hanya satu panggilan ke SQLPutData yang dapat dilakukan, dengan buffer yang berisi seluruh data. Untuk menyisipkan data panjang ke dalam kolom terenkripsi, gunakan API Salin Massal, yang dijelaskan di bagian berikutnya, dengan file data input.

Uang terenkripsi dan smallmoney

Kolom money atau smallmoney yang dienkripsi tidak dapat dijadikan target parameter, karena tidak ada tipe data ODBC spesifik yang dipetakan ke tipe tersebut, sehingga mengakibatkan error Operand Type Clash.

Salinan massal kolom terenkripsi

Penggunaan fungsi SQL Bulk Copy dan utilitas bcp didukung oleh Always Encrypted sejak ODBC Driver 17 for SQL Server. Baik plaintext (dienkripsi saat dimasukkan dan didekripsi saat diambil) maupun ciphertext (ditransfer apa adanya) dapat dimasukkan dan diambil menggunakan API Bulk Copy (bcp_*) dan utilitas bcp.

  • Untuk mengambil teks sandi dalam bentuk varbinary(max) (misalnya, untuk pemuatan massal ke basis data yang berbeda), buat koneksi tanpa opsi ColumnEncryption (atau atur ke Disabled) dan lakukan operasi BCP OUT.

  • Untuk menyisipkan dan mengambil teks biasa, dan biarkan driver secara transparan melakukan enkripsi dan dekripsi sesuai kebutuhan, pengaturan ColumnEncryption ke Enabled sudah cukup. Fungsionalitas API BCP tidak berubah.

  • Untuk menyisipkan ciphertext dalam bentuk varbinary(max) (misalnya, seperti yang diperoleh di atas), atur opsi BCPMODIFYENCRYPTED ke TRUE dan lakukan operasi BCP IN. Agar data hasilnya dapat didekripsi, pastikan bahwa CEK kolom tujuan sama dengan CEK asal ciphertext tersebut awalnya diperoleh.

Saat menggunakan utilitas bcp: Untuk mengontrol pengaturan ColumnEncryption, gunakan opsi -D dan tentukan DSN yang berisi nilai yang diinginkan. Untuk menyisipkan teks sandi, pastikan pengaturan ALLOW_ENCRYPTED_VALUE_MODIFICATIONS pengguna diaktifkan.

Tabel berikut ini menyediakan ringkasan tindakan saat beroperasi pada kolom terenkripsi:

ColumnEncryption Arah BCP Deskripsi
Disabled OUT (ke klien) Mengambil teks sandi. Jenis data yang diamati adalah varbinary(max).
Enabled OUT (ke klien) Mengambil teks biasa. Driver akan mendekripsi data kolom.
Disabled IN (ke server) Menyisipkan teks sandi. Pengaturan ini ditujukan untuk memindahkan data terenkripsi secara buram tanpa mengharuskannya didekripsi. Operasi akan gagal jika opsi ALLOW_ENCRYPTED_VALUE_MODIFICATIONS tidak ditetapkan untuk pengguna, atau BCPMODIFYENCRYPTED tidak ditetapkan pada handle koneksi. Untuk informasi selengkapnya, lihat di bawah ini.
Enabled IN (ke server) Sisipkan teks biasa. Driver akan mengenkripsi data kolom.

Opsi BCPMODIFYENCRYPTED

Untuk mencegah kerusakan data, server biasanya tidak mengizinkan penyisipan ciphertext langsung ke kolom terenkripsi, dan dengan demikian upaya untuk melakukannya akan gagal; namun, untuk pemuatan massal data terenkripsi menggunakan API BCP, mengatur BCPMODIFYENCRYPTEDopsi bcp_control ke TRUE akan memungkinkan ciphertext dimasukkan secara langsung, dan mengurangi risiko kerusakan data terenkripsi melalui pengaturan ALLOW_ENCRYPTED_VALUE_MODIFICATIONS opsi pada akun pengguna. Meskipun demikian, kunci harus cocok dengan data, dan ada baiknya melakukan beberapa pemeriksaan dalam mode hanya-baca terhadap data yang disisipkan setelah penyisipan massal dan sebelum data tersebut digunakan lebih lanjut.

Untuk informasi selengkapnya, lihat Memigrasikan Data Sensitif yang Dilindungi oleh Always Encrypted.

Ringkasan API Always Encrypted

Kata kunci string koneksi

Nama Deskripsi
ColumnEncryption Nilai yang diterima adalah Enabled/Disabled.
Enabled - mengaktifkan fungsionalitas Always Encrypted untuk koneksi.
Disabled - nonaktifkan fungsionalitas Always Encrypted untuk koneksi.
protokol atestasi, URL atestasi - (versi 17.4 dan yang lebih baru) memungkinkan Always Encrypted dengan enklave aman menggunakan protokol atestasi yang ditentukan dan URL atestasi.

Default adalah Disabled.
KeyStoreAuthentication Nilai yang Valid: KeyVaultPassword, KeyVaultClientSecret, KeyVaultInteractive, KeyVaultManagedIdentity
KeyStorePrincipalId Ketika KeyStoreAuthentication = KeyVaultPassword, atur nilai ini ke nama prinsipal pengguna Microsoft Entra yang valid.
Saat KeyStoreAuthentication = KeyVaultClientSecret mengatur nilai ini ke ID klien aplikasi Microsoft Entra yang valid
Ketika KeyStoreAuthentication = KeyVaultManagedIdentity, atur nilai ini ke ID objek identitas terkelola yang ditetapkan pengguna. Jika tidak ada nilai yang disediakan, identitas terkelola yang ditetapkan sistem akan digunakan.
KeyStoreSecret Ketika KeyStoreAuthentication = KeyVaultPassword mengatur nilai ini ke kata sandi untuk nama pengguna yang sesuai.
Saat KeyStoreAuthentication = KeyVaultClientSecret mengatur nilai ini ke rahasia aplikasi yang terkait dengan ID klien aplikasi Microsoft Entra yang valid

Atribut koneksi

Nama Tipe Deskripsi
SQL_COPT_SS_COLUMN_ENCRYPTION Sambungkan sebelumnya SQL_COLUMN_ENCRYPTION_DISABLE (0) - Nonaktifkan Always Encrypted
SQL_COLUMN_ENCRYPTION_ENABLE (1) - Aktifkan Always Encrypted
penunjuk ke string *attestation protocol*,*attestation URL* - (versi 17.4 atau yang lebih baru) aktifkan dengan Secure Enclave
SQL_COPT_SS_CEKEYSTOREPROVIDER Setelah terhubung [Set] - Mencoba memuat CEKeystoreProvider
[Get] - Mengembalikan nama CEKeystoreProvider
SQL_COPT_SS_CEKEYSTOREDATA Pasca-sambungan [Set] - Menulis data ke CEKeystoreProvider
[Get] - Baca data dari CEKeystoreProvider
SQL_COPT_SS_CEKCACHETTL Pasca-sambungan [Set] - Atur TTL cache CEK
[Get] - Ambil TTL cache CEK saat ini
SQL_COPT_SS_TRUSTEDCMKPATHS Setelah terhubung [Set] - Atur penunjuk jalur CMK tepercaya
[Get] - Dapatkan penunjuk jalur CMK tepercaya saat ini

Atribut dari pernyataan

Nama Deskripsi
SQL_SOPT_SS_COLUMN_ENCRYPTION SQL_CE_DISABLED (0) - Always Encrypted dinonaktifkan untuk pernyataan
SQL_CE_RESULTSETONLY (1) - dekripsi saja. Tataan hasil dan nilai pengembalian didekripsi, dan parameter tidak dienkripsi
SQL_CE_ENABLED (3) - Always Encrypted diaktifkan dan digunakan untuk parameter dan hasil

Bidang deskriptor

Bidang IPD Ukuran/Jenis Nilai Bawaan Deskripsi
SQL_CA_SS_FORCE_ENCRYPT (1236) WORD (2 byte) 0 Ketika 0 (default): keputusan untuk mengenkripsi parameter ini ditentukan oleh ketersediaan metadata enkripsi.

Saat bernilai nonzero: jika metadata enkripsi tersedia untuk parameter ini, parameter ini akan dienkripsi. Jika tidak, permintaan gagal dengan kesalahan [CE300] [Microsoft][ODBC Driver 17 untuk SQL Server]Enkripsi wajib ditentukan untuk parameter tetapi tidak ada metadata enkripsi yang disediakan oleh server.

opsi bcp_control

Nama Opsi Nilai Bawaan Deskripsi
BCPMODIFYENCRYPTED (21) SALAH Ketika TRUE, memungkinkan nilai varbinary(max) dimasukkan ke dalam kolom terenkripsi. Saat bernilai FALSE, mencegah penyisipan kecuali jika tipe yang benar dan metadata enkripsi disertakan.

Pemecahan Masalah

Saat mengalami kesulitan menggunakan Always Encrypted, mulailah dengan memeriksa poin-poin berikut:

  • CEK yang mengenkripsi kolom yang diinginkan ada dan dapat diakses di server.

  • CMK yang mengenkripsi CEK memiliki metadata yang dapat diakses di server dan juga dapat diakses dari klien.

  • ColumnEncryption diaktifkan di DSN, string koneksi, atau atribut koneksi, dan, jika menggunakan enklave aman, memiliki format yang benar.

Selain itu, saat menggunakan enklave aman, kegagalan pengesahan mengidentifikasi langkah dalam proses pengesahan di mana kegagalan terjadi, sesuai dengan tabel berikut:

Langkah Deskripsi
0-99 Respons pengesahan tidak valid, atau kesalahan verifikasi tanda tangan.
100-199 Kesalahan saat mengambil sertifikat dari URL pengesahan. Pastikan <attestation URL>/v2.0/signingCertificates valid dan dapat diakses.
200-299 Format identitas enklave yang tidak terduga atau salah.
300-399 Kesalahan saat membuat saluran aman dengan enklave.

Lihat juga