Utilisation d’Always Encrypted avec ODBC Driver for SQL Server
Applicable à
- ODBC Driver 13.1+ for SQL Server
Introduction
Cet article fournit des informations sur la façon de développer des applications ODBC à l’aide d’Always Encrypted (moteur de base de données) ou Always Encrypted avec enclaves sécurisées et du Pilote ODBC pour SQL Server.
Always Encrypted permet aux applications clientes de chiffrer des données sensibles et de ne jamais révéler les données ou les clés de chiffrement à SQL Server ou Azure SQL Database. Pour garantir cette sécurité, un pilote activé avec Always Encrypted, tel que le pilote ODBC Driver pour SQL Server, chiffre et déchiffre de manière transparente les données sensibles dans l’application cliente. Le pilote détermine automatiquement les paramètres de requêtes qui correspondent aux colonnes de base de données sensibles (protégées avec Always Encrypted) et chiffre les valeurs de ces paramètres avant de transmettre les données à SQL Server ou Azure SQL Database. De même, il déchiffre de manière transparente les données récupérées dans les colonnes de base de données chiffrées, qui figurent dans les résultats de la requête. Always Encrypted avec les enclaves sécurisées étend cette fonctionnalité pour activer des fonctionnalités plus complexes sur les données sensibles tout en préservant la confidentialité des données.
Pour plus d’informations, consultez Always Encrypted (Moteur de base de données) et Always Encrypted avec enclaves sécurisées.
Prérequis
Configurez Always Encrypted dans votre base de données. Ce processus consiste à provisionner des clés Always Encrypted et à configurer le chiffrement pour les colonnes de base de données sélectionnées. Si vous n’avez pas encore de base de données configurée avec Always Encrypted, suivez les instructions du Tutoriel : bien démarrer avec Always Encrypted. En particulier, votre base de données doit contenir les définitions de métadonnées pour une clé principale de colonne (CMK), une clé de chiffrement de colonne (CEK) et une table contenant une ou plusieurs colonnes chiffrées à l’aide de cette clé CEK.
Si vous utilisez Always Encrypted avec enclaves sécurisées, consultez Développer des applications en utilisant Always Encrypted avec enclaves sécurisées pour connaître les autres prérequis.
Activation d’Always Encrypted dans une application ODBC
Le moyen le plus simple d’activer à la fois le chiffrement des paramètres et le déchiffrement des colonnes chiffrées des jeux de résultats consiste à affecter la valeur Enabled au mot clé de chaîne de connexion ColumnEncryption
. Voici un exemple de chaîne de connexion activant Always Encrypted :
SQLWCHAR *connString = L"Driver={ODBC Driver 18 for SQL Server};Server={myServer};Encrypt=yes;Trusted_Connection=yes;ColumnEncryption=Enabled;";
Vous pouvez aussi activer Always Encrypted dans la configuration de source de données, à l’aide des mêmes clé et valeur (qui seront remplacées par le paramètre de chaîne de connexion, s’il est présent), ou par programmation avec l’attribut de préconnexion SQL_COPT_SS_COLUMN_ENCRYPTION
. Procéder de cette façon substitue la valeur définie dans la chaîne de connexion ou la source de données :
SQLSetConnectAttr(hdbc, SQL_COPT_SS_COLUMN_ENCRYPTION, (SQLPOINTER)SQL_COLUMN_ENCRYPTION_ENABLE, 0);
Une fois Always Encrypted activé pour la connexion, son comportement peut être ajusté pour des requêtes individuelles. Pour plus d’informations, consultez Contrôle de l’impact d’Always Encrypted sur les performances, ci-dessous.
L’activation de la fonctionnalité Always Encrypted ne suffit pas à la réussite du chiffrement ou du déchiffrement ; vous devez également garantir ce qui suit :
L’application dispose des autorisations de base de données VIEW ANY COLUMN MASTER KEY DEFINITION et VIEW ANY COLUMN ENCRYPTION KEY DEFINITION qui sont nécessaires pour accéder aux métadonnées des clés Always Encrypted dans la base de données. Pour plus d’informations, consultez Autorisations de base de données.
L’application peut accéder à la clé CMK qui protège les clés CEK pour les colonnes chiffrées interrogées. Ce comportement est dépendant du fournisseur de magasin de clés qui stocke la clé CMK. Pour plus d’informations, consultez Utilisation de magasins de clés principales de colonne.
Activation d’Always Encrypted avec des enclaves sécurisées
Notes
Sur Linux et macOS, la version 1.0.1 ou une version ultérieure d’OpenSSL est nécessaire pour pouvoir utiliser Always Encrypted avec enclaves sécurisées.
À partir de la version 17.4, le pilote prend en charge Always Encrypted avec enclaves sécurisées. Pour activer l’utilisation de l’enclave lors de la connexion à une base de données, définissez la clé DSN ColumnEncryption
, le mot clé de la chaîne de connexion ou l’attribut de connexion sur la valeur <attestation protocol>,<attestation URL>
, où :
<attestation protocol>
: spécifie un protocole utilisé pour l’attestation d’enclave.- Si vous utilisez SQL Server et le service Guardian hôte (SGH),
<attestation protocol>
doit êtreVBS-HGS
. - Si vous utilisez Azure SQL Database et Microsoft Azure attestation,
<attestation protocol>
doit êtreSGX-AAS
. - Si vous n’avez pas besoin d’attestation,
<attestation-protocol>
doit êtreVBS-NONE
. (Version 18.1+)
- Si vous utilisez SQL Server et le service Guardian hôte (SGH),
<attestation URL>
: spécifie une URL d’attestation (un point de terminaison de service d’attestation). Vous devez obtenir une URL d’attestation pour votre environnement auprès de votre administrateur de services fédérés d’attestation.- Si vous utilisez SQL Server et le service Guardian hôte (SGH), consultez Déterminer et partager l’URL d’attestation SGH.
- Si vous utilisez Azure SQL Database et Microsoft Azure Attestation, consultez Déterminer l’URL d’attestation de votre stratégie d’attestation.
- Si vous n’avez pas besoin d’attestation, ne spécifiez pas d’URL d’attestation (ni la virgule précédente). (Version 18.1+)
Exemples de chaînes de connexion autorisant les calculs d’enclave pour une connexion de base de données :
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=myPassword;Encrypt=yes;ColumnEncryption=SGX-AAS,https://myAttestationProvider.uks.attest.azure.net/"
Aucune attestation (v18.1+) :
"Driver=ODBC Driver 18 for SQL Server;Server=myServer.database.windows.net;Database=myDataBase;Uid=myUsername;Pwd=myPassword;Encrypt=yes;ColumnEncryption=VBS-NONE"
Si le serveur et le service d’attestation sont configurés correctement, de même que les clés CMK et CEK avec enclave pour les colonnes chiffrées, vous pouvez exécuter des requêtes qui utilisent l’enclave (par exemple le chiffrement sur place et les calculs complexes) en plus des fonctionnalités déjà fournies par Always Encrypted. Pour plus d’informations, consultez Configurer Always Encrypted avec enclaves sécurisées.
Récupération et modification des données dans des colonnes chiffrées
Une fois que vous avez activé Always Encrypted sur une connexion, vous pouvez utiliser les API ODBC standard. Les API ODBC peuvent récupérer ou modifier des données dans des colonnes de base de données chiffrées. Les éléments de documentation suivants peuvent vous être utiles :
Votre application doit disposer des autorisations de base de données requises, et avoir accès à la clé principale de colonne. Ensuite, le pilote chiffre tous les paramètres de requête qui ciblent des colonnes chiffrées. Il déchiffre également les données récupérées à partir de colonnes chiffrées. Il effectue toutes ces opérations de chiffrement et de déchiffrement sans aucune assistance de la part de votre code source. Pour votre programme, c’est comme si les colonnes n’étaient pas chiffrées.
Si Always Encrypted n’est pas activé, les requêtes ayant des paramètres qui ciblent des colonnes chiffrées échouent. Les données peuvent toujours être récupérées à partir des colonnes chiffrées, tant que la requête n’a aucun paramètre qui cible des colonnes chiffrées. Toutefois, le pilote ne tente aucun déchiffrement. L’application reçoit les données chiffrées binaires (sous la forme de tableaux d’octets).
Le tableau ci-dessous récapitule le comportement des requêtes, selon qu’Always Encrypted est activé ou non :
Caractéristique de la requête | Always Encrypted est activé et l’application peut accéder aux clés et à leurs métadonnées | Always Encrypted est activé et l’application ne peut pas accéder aux clés et à leurs métadonnées | Always Encrypted est désactivé |
---|---|---|---|
Paramètres ciblant des colonnes chiffrées. | Des valeurs de paramètres sont chiffrées en toute transparence. | Error | Error |
Récupération des données à partir de colonnes chiffrées, sans paramètres ciblant des colonnes chiffrées. | Les résultats de colonnes chiffrées sont déchiffrés de manière transparente. L’application reçoit des valeurs de colonne en texte clair. | Error | Les résultats des colonnes chiffrées ne sont pas déchiffrés. L’application reçoit des valeurs chiffrées sous la forme de tableaux d’octets. |
Les exemples suivants illustrent la récupération et la modification de données dans des colonnes chiffrées. Les exemples partent du principe que la table a le schéma suivant. Les colonnes SSN et BirthDate sont chiffrées.
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
Exemple d’insertion de données
Cet exemple insère une ligne dans la table Patients. Notez les points suivants :
L’exemple de code ne contient aucun élément spécifique au chiffrement. Le pilote détecte et chiffre automatiquement les valeurs des paramètres de date et SSN, qui ciblent des colonnes chiffrées. Ce comportement rend le chiffrement transparent pour l’application.
Les valeurs insérées dans les colonnes de base de données, y compris les colonnes chiffrées, sont transmises sous forme de paramètres liés (voir Fonction SQLBindParameter). L’utilisation de paramètres est facultative lors de l’envoi de valeurs aux colonnes non chiffrées (même si elle est vivement recommandée, car elle contribue à empêcher l’injection SQL), mais elle est nécessaire pour les valeurs qui ciblent des colonnes chiffrées. Si les valeurs insérées dans les colonnes SSN ou BirthDate ont été passées en tant que littéraux incorporés dans l’instruction de requête, la requête échoue car le pilote ne tente pas de chiffrer ou de traiter les littéraux dans les requêtes. Par conséquent, le serveur les rejettera en les considérant comme incompatibles avec les colonnes chiffrées.
Le type SQL du paramètre inséré dans la colonne SSN est défini sur SQL_CHAR, qui mappe au type de données SQL Server char (
rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 11, 0, (SQLPOINTER)SSN, 0, &cbSSN);
). Si le type du paramètre était défini sur SQL_WCHAR (correspondant à nchar), la requête échouerait. En effet, Always Encrypted ne prend pas en charge les conversions côté serveur de valeurs nchar chiffrées en valeurs char chiffrées. Pour plus d’informations sur les mappages de type de données, consultez Guide de référence du programmeur ODBC – Annexe D : Types de données.
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);
Exemple d’extraction de données en texte clair
L’exemple suivant montre le filtrage de données basé sur des valeurs chiffrées, ainsi que la récupération de données en texte clair à partir de colonnes chiffrées. Notez les points suivants :
La valeur utilisée dans la clause WHERE pour filtrer la colonne SSN doit être transmise avec SQLBindParameter, afin que le pilote puisse la chiffrer de manière transparente avant de l’envoyer au serveur.
Toutes les valeurs imprimées par le programme sont en texte clair, car le pilote déchiffre de manière transparente les données récupérées à partir des colonnes SSN et BirthDate.
Notes
Les requêtes peuvent effectuer des comparaisons d’égalité sur des colonnes chiffrées uniquement si le chiffrement est déterministe ou si l’enclave sécurisée est activée.
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);
}
Exemple d’extraction de données chiffrées
Si Always Encrypted n’est pas activé, une requête peut toujours récupérer des données à partir de colonnes chiffrées, tant qu’aucun de ses paramètres ne ciblent des colonnes chiffrées.
L’exemple suivant illustre la récupération de données chiffrées binaires à partir de colonnes chiffrées. Notez les points suivants :
- Étant donné qu’Always Encrypted n’est pas activé dans la chaîne de connexion, la requête retourne des valeurs SSN et BirthDate chiffrées sous la forme de tableaux d’octets (le programme convertit les valeurs en chaînes).
- Une requête qui récupère des données à partir de colonnes chiffrées lorsqu’Always Encrypted est désactivé peut avoir des paramètres, tant qu’aucun d’eux ne cible une colonne chiffrée. La requête ci-dessus filtre par nom (LastName), qui n’est pas chiffré dans la base de données. Si la requête filtre par SSN ou BirthDate, la requête échoue.
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);
}
Chiffrement de money/smallmoney
À partir de la version 17.7 du pilote, il est possible d’utiliser Always Encrypted avec MONEY et SMALLMONEY. Quelques étapes supplémentaires sont cependant nécessaires. Lors de l’insertion dans des colonnes MONEY ou SMALLMONEY chiffrées, utilisez un des types C suivants :
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
et un type SQL SQL_NUMERIC
ou SQL_DOUBLE
(la précision peut être perdue lors de l’utilisation de ce type).
Liaison de la variable
Lors de la liaison d’une variable MONEY/SMALLMONEY dans une colonne chiffrée, le ou les champs de descripteur suivants doivent être définis :
// 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);
Éviter les problèmes courants lors de l’interrogation de colonnes chiffrées
Cette section décrit des catégories d’erreurs courantes liées à l’interrogation des colonnes chiffrées à partir d’applications ODBC et fournit des conseils sur la façon de les éviter.
Erreurs liées à la conversion de types de données non pris en charge
Always Encrypted ne prend en charge que peu de conversions de types de données chiffrées. Pour obtenir la liste détaillée des conversions de types prises en charge, consultez Always Encrypted (moteur de base de données). Pour éviter les erreurs de conversion de types de données, veillez à observer les points suivants lors de l’utilisation de SQLBindParameter avec des paramètres ciblant des colonnes chiffrées :
Le type SQL du paramètre est exactement le même que le type de la colonne cible, ou la conversion du type SQL vers le type de la colonne est prise en charge.
La précision et l’échelle des paramètres ciblant les colonnes des types de données SQL Server
decimal
etnumeric
sont les mêmes que celles configurées pour la colonne cible.La précision des paramètres ciblant les colonnes des types de données SQL Server
datetime2
,datetimeoffset
outime
n’est pas supérieure à celle de la colonne cible dans les requêtes qui modifient les valeurs de la colonne cible.
Erreurs dues au passage de texte en clair au lieu de valeurs chiffrées
Toute valeur qui cible une colonne chiffrée doit être chiffrée avant d’être envoyée au serveur. Toute tentative d’insertion, de modification ou de filtrage par une valeur en texte clair dans une colonne chiffrée entraîne une erreur. Pour éviter ces erreurs, effectuez les vérifications suivantes :
Always Encrypted est activé (dans la source de données, la chaîne de connexion, avant d’établir la connexion en définissant l’attribut de connexion
SQL_COPT_SS_COLUMN_ENCRYPTION
pour une connexion spécifique, ou l’attribut d’instructionSQL_SOPT_SS_COLUMN_ENCRYPTION
pour une instruction spécifique).Utilisez SQLBindParameter pour envoyer des données ciblant des colonnes chiffrées. L’exemple ci-dessous illustre une requête qui filtre incorrectement une colonne chiffrée (SSN) à l’aide d’un littéral/d’une constante, au lieu de passer le littéral comme argument à SQLBindParameter.
string queryText = "SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE SSN='795-73-9838'";
Précautions en cas d’utilisation de SQLSetPos et SQLMoreResults
SQLSetPos
L’API SQLSetPos
permet à une application de mettre à jour des lignes dans un jeu de résultats à l’aide de mémoires tampons qui ont été liées avec SQLBindCol et dans lesquelles des lignes de données ont été extraites précédemment. En raison du comportement de remplissage asymétrique des types de longueur fixe chiffrés, il est possible de modifier de façon inattendue les données de ces colonnes en effectuant des mises à jour sur d’autres colonnes de la ligne. Avec AE, les valeurs de caractères de longueur fixe seront complétées si la valeur est inférieure à la taille de la mémoire tampon.
Pour atténuer ce comportement, utilisez l’indicateur SQL_COLUMN_IGNORE
afin d’ignorer les colonnes qui ne seront pas mises à jour pendant SQLBulkOperations
et pendant les mises à jour basées sur curseur effectuées avec SQLSetPos
. Toutes les colonnes qui ne sont pas modifiées directement par l’application doivent être ignorées, à la fois pour des raisons de performances et pour éviter la troncation des colonnes qui sont liées à une mémoire tampon plus petite que leur taille réelle (DB). Pour plus d’informations, consultez la référence de fonction SQLSetPos.
SQLMoreResults et SQLDescribeCol
Les programmes d’application peuvent appeler SQLDescribeCol pour retourner des métadonnées concernant les colonnes dans des instructions préparées. Quand Always Encrypted est activé, si SQLMoreResults
est appelé avant SQLDescribeCol
, sp_describe_first_result_set est appelé. Or, cette fonction ne retourne pas correctement les métadonnées en clair des colonnes chiffrées. Pour éviter ce problème, appelez SQLDescribeCol
sur les instructions préparées avant d’appeler SQLMoreResults
.
Contrôle de l’impact d’Always Encrypted sur les performances
Always Encrypted étant une technologie de chiffrement côté client, la dégradation des performances s’observe côté client, et non dans la base de données. Outre le coût des opérations de chiffrement et de déchiffrement, les autres sources de dégradation des performances côté client sont les suivantes :
Allers-retours supplémentaires avec la base de données afin de récupérer des métadonnées pour les paramètres de requête.
Appels au magasin de clés principales de colonne pour accéder à une clé principale de colonne.
Cette section décrit les outils intégrés d’optimisation des performances dans ODBC Driver for SQL Server et comment vous pouvez contrôler l’impact des deux facteurs ci-dessus sur les performances.
Contrôle des allers-retours pour récupérer les métadonnées des paramètres de requête
Si Always Encrypted est activé pour une connexion, le pilote appelle par défaut sys.sp_describe_parameter_encryption pour chaque requête paramétrable, en passant l’instruction de requête (sans valeurs de paramètre) à SQL Server. Cette procédure stockée analyse l’instruction de requête afin de savoir si des paramètres doivent être chiffrés. Si c’est le cas, elle retourne pour chaque paramètre des informations relatives au chiffrement qui permettent au pilote de les chiffrer. Ce comportement garantit un niveau élevé de transparence à l’application cliente : l’application (de même que le développeur d’application) n’a pas besoin de savoir quelles requêtes accèdent à des colonnes chiffrées, tant que les valeurs ciblant des colonnes chiffrées sont transmises au pilote dans les paramètres.
À partir de la version 17.6, le pilote met également en cache les métadonnées de chiffrement pour les instructions préparées. Le niveau de performance s’en trouve amélioré, car les appels ultérieurs à SQLExecute
n’ont pas besoin d’un aller-retour supplémentaire pour récupérer les métadonnées de chiffrement.
Comportement d’Always Encrypted instruction par instruction
Pour contrôler l’impact sur les performances de la récupération des métadonnées de chiffrement pour les requêtes paramétrables, vous pouvez modifier le comportement d’Always Encrypted pour chaque requête s’il a été activé sur la connexion. De cette façon, sys.sp_describe_parameter_encryption
est appelé uniquement pour les requêtes dont les paramètres ciblent des colonnes chiffrées. Notez toutefois que, de cette façon, la transparence du chiffrement est amoindrie : si vous chiffrez davantage de colonnes dans votre base de données, vous devrez peut-être modifier le code de votre application pour l’aligner sur les modifications du schéma.
Pour contrôler le comportement Always Encrypted d’une instruction, appelez SQLSetStmtAttr afin d’affecter l’une des valeurs suivantes à l’attribut d’instruction SQL_SOPT_SS_COLUMN_ENCRYPTION
:
Valeur | Description |
---|---|
SQL_CE_DISABLED (0) |
Always Encrypted est désactivé pour l’instruction |
SQL_CE_RESULTSETONLY (1) |
Déchiffrement uniquement. Les jeux de résultats et les valeurs retournées sont déchiffrés, et les paramètres ne sont pas chiffrés. |
SQL_CE_ENABLED (3) |
Always Encrypted est activé et utilisé pour les paramètres et les résultats |
Les nouveaux handles d’instructions créés à partir d’une connexion avec Always Encrypted activé utilisent par défaut SQL_CE_ENABLED. Les handles créés à partir d’une connexion avec Always Encrypted désactivé utilisent par défaut SQL_CE_DISABLED (et il n’est pas possible d’activer Always Encrypted sur ces handles).
Si la plupart des requêtes d’une application cliente accèdent à des colonnes chiffrées, suivez ces recommandations :
Affectez au mot clé de chaîne de connexion
ColumnEncryption
la valeurEnabled
.Affectez la valeur
SQL_CE_DISABLED
à l’attributSQL_SOPT_SS_COLUMN_ENCRYPTION
sur les instructions qui n’accèdent à aucune colonne chiffrée. Ce paramètre empêchera à la fois l’appel àsys.sp_describe_parameter_encryption
et les tentatives de déchiffrement des valeurs du jeu de résultats.Affectez la valeur
SQL_CE_RESULTSETONLY
à l’attributSQL_SOPT_SS_COLUMN_ENCRYPTION
sur les instructions qui ne comportent aucun paramètre exigeant un chiffrement, mais qui récupèrent des données à partir de colonnes chiffrées. Ce paramètre empêchera l’appel àsys.sp_describe_parameter_encryption
et le chiffrement des paramètres. Les résultats contenant des colonnes chiffrées continueront à être déchiffrés.Utilisez des instructions préparées pour les requêtes qui seront exécutées plusieurs fois. Préparez la requête avec
SQLPrepare
et enregistrez le handle d’instruction. Réutilisez-le avecSQLExecute
chaque fois qu’il est exécuté. Cette méthode est l’approche recommandée pour les performances, même en l’absence de colonnes chiffrées ; elle permet au pilote d’exploiter les métadonnées mises en cache.
Paramètres de sécurité d’Always Encrypted
Forcer le chiffrement de colonne
Pour appliquer le chiffrement d’un paramètre, définissez le champ de descripteur de paramètre d’implémentation (IPD) SQL_CA_SS_FORCE_ENCRYPT
par le biais d’un appel à la fonction SQLSetDescField. Si la valeur est différente de zéro, le pilote retourne une erreur quand aucune métadonnée de chiffrement n’est retournée pour le paramètre associé.
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);
Si SQL Server informe le pilote qu’aucun chiffrement n’est nécessaire pour le paramètre. Les requêtes qui utilisent ce dernier échouent. Ce comportement offre une protection supplémentaire contre les attaques au niveau de la sécurité durant lesquelles une machine SQL Server compromise fournit des métadonnées de chiffrement incorrectes au client, ce qui peut entraîner la divulgation de données.
Mise en cache des clés de chiffrement de colonne
Afin de réduire le nombre d’appels à un magasin de clés principales de colonne pour déchiffrer les clés de chiffrement de colonne, le pilote met en cache les clés CEK en clair dans la mémoire. Le cache de clés CEK est global pour le pilote et non associé à une connexion spécifique. Après avoir reçu la clé CEK chiffrée à partir des métadonnées de la base de données, le pilote tente d’abord de trouver la clé CEK en clair correspondant à la valeur de clé chiffrée qui se trouve dans le cache. Le pilote appelle le magasin de clés contenant la clé CMK uniquement s’il ne trouve pas la clé CEK en clair correspondante dans le cache.
Notes
Dans ODBC Driver for SQL Server, les entrées dans le cache sont supprimées après un délai d’attente de deux heures. Ce comportement signifie que, pour une clé CEK chiffrée, le pilote ne contacte le magasin de clés qu’une seule fois au cours de la durée de vie de l’application, ou toutes les deux heures, la plus petite des deux valeurs étant retenue.
À compter d’ODBC Driver 17.1 for SQL Server, vous pouvez ajuster le délai d’expiration du cache de clés CEK à l’aide de l’attribut de connexion SQL_COPT_SS_CEKCACHETTL
, qui spécifie le nombre de secondes pendant lesquelles une clé CEK restera dans le cache. En raison de la nature globale du cache, cet attribut peut être ajusté à partir de n’importe quel handle de connexion valide pour le pilote. Quand la durée de vie du cache est réduite, les clés CEK existantes qui dépasseraient la nouvelle durée de vie sont également supprimées. Si la durée de vie est égale à 0, aucune clé CEK n’est mise en cache.
Chemins de clés approuvés
À compter d’ODBC Driver 17.1 for SQL Server, l’attribut de connexion SQL_COPT_SS_TRUSTEDCMKPATHS
permet à une application d’exiger que les opérations Always Encrypted utilisent uniquement une liste de clés CMK spécifiée, identifiées par leurs chemins de clé. Par défaut, cet attribut est NULL, ce qui signifie que le pilote accepte n’importe quel chemin de clé. Pour utiliser cette fonctionnalité, définissez SQL_COPT_SS_TRUSTEDCMKPATHS
de façon à pointer vers une chaîne à caractères larges délimitée par des caractères Null et se terminant par un caractère Null, qui liste les chemins de clés autorisés. La mémoire vers laquelle pointe cet attribut doit rester valide pendant les opérations de chiffrement et de déchiffrement utilisant le handle de connexion sur lequel elle est définie. Le pilote vérifie alors si le chemin de la clé CMK spécifié par les métadonnées du serveur figure dans cette liste (sans respect de la casse). Si le chemin est absent de la liste, l’opération échoue. L’application peut changer le contenu de la mémoire vers laquelle cet attribut pointe, afin de modifier sa liste de clés CMK approuvées, sans redéfinir l’attribut.
Utilisation de magasins de clés principales de colonne
Pour chiffrer ou déchiffrer des données, le pilote doit obtenir une clé CEK configurée pour la colonne cible. Les clés CEK sont stockées sous forme chiffrée (on parle alors de clés ECEK) dans les métadonnées de la base de données. Chaque clé CEK a une clé CMK correspondante qui a été utilisée pour la chiffrer. Les métadonnées de base de données ne stockent pas la clé CMK proprement dite ; elles contiennent uniquement le nom du magasin de clés et des informations que ce dernier peut utiliser pour trouver la clé CMK.
Pour obtenir la valeur de texte en clair d’une clé ECEK, le pilote obtient d’abord les métadonnées relatives à la clé CEK et sa clé CMK correspondante, il utilise ces informations pour contacter le magasin de clés contenant la clé CMK, puis il lui demande de déchiffrer la clé ECEK. Le pilote communique avec un magasin de clés à l’aide d’un fournisseur de magasin de clés.
Fournisseurs de magasins de clés intégrés
ODBC Driver for SQL Server est fourni avec les fournisseurs de magasins de clés intégrés suivants :
Nom | Description | Nom du fournisseur (de métadonnées) | Disponibilité |
---|---|---|---|
Azure Key Vault | Stocke les clés CMK dans un coffre de clés Azure | AZURE_KEY_VAULT |
Windows, macOS, Linux |
Magasin de certificats Windows | Stocke les clés CMK localement dans le magasin de clés Windows | MSSQL_CERTIFICATE_STORE |
Windows |
Vous (ou votre administrateur de base de données) devez vérifier que le nom du fournisseur (configuré dans les métadonnées de clé principale de colonne) est correct et que le chemin de la clé principale de colonne est conforme au format du chemin de clé pour le fournisseur donné. Nous vous recommandons de configurer les clés à l’aide d’outils tels que SQL Server Management Studio. Cet outil génère automatiquement des noms de fournisseurs et des chemins de clés valides lorsque l’instruction CREATE COLUMN MASTER KEY (Transact-SQL) est émise.
Vérifiez que votre application peut accéder à la clé dans le magasin de clés. Pour ce processus, vous devez peut-être accorder à votre application l’accès à la clé ou au magasin de clés (en fonction de ce dernier), ou suivre d’autres étapes de configuration propres au magasin de clés. Par exemple, pour accéder à un coffre de clés Azure Key Vault, vous devrez fournir les informations d’identification correctes au magasin de clés.
Utilisation du fournisseur Azure Key Vault
Azure Key Vault (AKV) est un outil est très pratique qui permet de stocker et de gérer des clés principales de colonne Always Encrypted, en particulier si vos applications sont hébergées dans Azure. ODBC Driver for SQL Server sur Linux, macOS et Windows inclut un fournisseur de magasin de clés principales de colonne intégré pour Azure Key Vault. Pour plus d’informations sur la configuration d’un coffre Azure Key Vault pour Always Encrypted, consultez Azure Key Vault – Étape par étape, Bien démarrer avec Key Vault et Création de clés principales de colonne dans Azure Key Vault.
Remarque
Le pilote ODBC prend en charge uniquement l’authentification AKV directe auprès de Microsoft Entra ID (anciennement Azure Active Directory). Si vous utilisez l’authentification Microsoft Entra auprès d’AKV et que votre configuration exige l’authentification auprès d’un point de terminaison Active Directory Federation Services, l’authentification risque d’échouer.
Sur Linux et macOS, pour les versions 17.2 et ultérieures du pilote, libcurl
est nécessaire pour utiliser ce fournisseur, mais n’est pas une dépendance explicite dans la mesure où les autres opérations avec le pilote n’en ont pas besoin. Si vous rencontrez une erreur concernant libcurl
, vérifiez qu’il est installé.
Le pilote prend en charge l’authentification auprès d’Azure Key Vault avec les types d’informations d’identification suivants :
Nom d’utilisateur / mot de passe : avec cette méthode, les informations d’identification sont le nom d’un utilisateur Microsoft Entra et son mot de passe.
ID client/secret : avec cette méthode, les informations d’identification sont un ID de client d’application et un secret d’application.
Identité managée (17.5.2+) – affectée par le système ou l’utilisateur ; pour plus d’informations, consultez Identités managées pour les ressources Azure.
Azure Key Vault interactif (pilotes Windows 17.7+) : avec cette méthode, les informations d’identification sont authentifiées via Microsoft Entra ID avec l’ID de connexion.
Pour autoriser le pilote à utiliser des clés CMK stockées dans Azure Key Vault pour le chiffrement de colonne, utilisez les mots clés de chaîne de connexion uniquement suivants :
Type d'informations d'identification | KeyStoreAuthentication |
KeyStorePrincipalId |
KeyStoreSecret |
---|---|---|---|
Nom d'utilisateur/mot de passe | KeyVaultPassword |
Nom d’utilisateur principal | Mot de passe |
ID client/secret | KeyVaultClientSecret |
ID client | Secret |
Identité managée | KeyVaultManagedIdentity |
ID d’objet (facultatif, affecté par l’utilisateur uniquement) | (non spécifié) |
AKV interactif | KeyVaultInteractive |
(non défini) | (non défini) |
À compter de la version v17.8, KeyStoreAuthentication et KeyStorePrincipalId peuvent être modifiés dans l’interface utilisateur de configuration DSN dans l’administrateur de source de données ODBC.
Exemples de chaîne de connexion
Les chaînes de connexion suivantes montrent comment s’authentifier auprès d’Azure Key Vault avec les deux types d’informations d’identification :
ID client/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>"
Nom d’utilisateur/mot de passe
"DRIVER=ODBC Driver 18 for SQL Server;SERVER=myServer;Encrypt=yes;Trusted_Connection=Yes;DATABASE=myDB;ColumnEncryption=Enabled;KeyStoreAuthentication=KeyVaultPassword;KeyStorePrincipalId=<username>;KeyStoreSecret=<password>"
Identité managée (affectée par le système)
"DRIVER=ODBC Driver 18 for SQL Server;SERVER=myServer;Encrypt=yes;Trusted_Connection=Yes;DATABASE=myDB;ColumnEncryption=Enabled;KeyStoreAuthentication=KeyVaultManagedIdentity"
Identité managée (affectée par l’utilisateur)
"DRIVER=ODBC Driver 18 for SQL Server;SERVER=myServer;Encrypt=yes;Trusted_Connection=Yes;DATABASE=myDB;ColumnEncryption=Enabled;KeyStoreAuthentication=KeyVaultManagedIdentity;KeyStorePrincipalId=<objectID>"
AKV interactif
"DRIVER=ODBC Driver 18 for SQL Server;SERVER=myServer;Encrypt=yes;Trusted_Connection=Yes;DATABASE=myDB;ColumnEncryption=Enabled;KeyStoreAuthentication=KeyVaultInteractive;UID=<userID>;PWD=<password>"
Aucune autre modification d’application ODBC n’est requise pour utiliser Azure Key Vault pour le stockage des clés CMK.
Notes
Le pilote contient la liste des points de terminaison AKV auxquels il fait confiance. À partir de la version 17.5.2 du pilote, cette liste est configurable : définissez la propriété AKVTrustedEndpoints
dans la clé de Registre (Windows) ODBCINST.INI ou ODBC.INI ou dans la section du fichier odbcinst.ini
ou odbc.ini
(Linux/macOS) du pilote ou du DNS sous forme de liste délimitée par des points-virgules. En la définissant dans le DSN, elle devient prioritaire par rapport à un paramètre du pilote. Si la valeur commence par un point-virgule, elle étend la liste par défaut ; sinon, elle la remplace. La liste par défaut (à partir de 17.5) est vault.azure.net;vault.azure.cn;vault.usgovcloudapi.net;vault.microsoftazure.de
. À compter de 17.7, la liste inclut également managedhsm.azure.net;managedhsm.azure.cn;managedhsm.usgovcloudapi.net;managedhsm.microsoftazure.de
.
Notes
Le fournisseur Azure Key Vault intégré au pilote ODBC prend en charge à la fois les coffres et les HSM managés dans Azure Key Vault.
Utilisation du fournisseur du magasin de certificats Windows
ODBC Driver for SQL Server sur Windows inclut un fournisseur de magasin de clés CMK intégré pour le Magasin de certificats Windows, nommé MSSQL_CERTIFICATE_STORE
. (Ce fournisseur n’est pas disponible sur macOS ni Linux.) Avec ce fournisseur, la clé CMK est stockée localement sur la machine cliente. Aucune configuration supplémentaire n’est nécessaire pour que l’application puisse l’utiliser avec le pilote. Toutefois, l’application doit avoir accès au certificat et à sa clé privée dans le magasin. Pour plus d’informations, consultez Créer et stocker des clés principales de colonne (Always Encrypted).
Utilisation de fournisseurs de magasins de clés personnalisés
ODBC Driver for SQL Server prend également en charge les fournisseurs de magasins de clés tiers personnalisés à l’aide de l’interface CEKeystoreProvider. Cette fonctionnalité permet à une application de charger, d’interroger et de configurer des fournisseurs de magasin de clés afin que le pilote puisse les utiliser pour accéder aux colonnes chiffrées. Les applications peuvent également interagir directement avec un fournisseur de magasin de clés afin de chiffrer des clés CEK pour le stockage dans SQL Server, et effectuer des tâches au-delà de l’accès aux colonnes chiffrées avec ODBC. Pour plus d’informations, consultez Fournisseurs de magasins de clés personnalisés.
Deux attributs de connexion sont utilisés pour interagir avec les fournisseurs de magasins de clés personnalisés. Il s'agit de :
SQL_COPT_SS_CEKEYSTOREPROVIDER
SQL_COPT_SS_CEKEYSTOREDATA
Le premier sert à charger et à énumérer les fournisseurs de magasins de clés chargés, tandis que le second autorise les communications avec les fournisseurs d’applications. Ces attributs de connexion peuvent être utilisés à tout moment, avant ou après avoir établi une connexion. En effet, l’interaction entre l’application et le fournisseur n’implique pas de communication avec SQL Server. Toutefois, le pilote n’a pas encore été chargé : si vous définissez et récupérez ces attributs avant de vous connecter, ils seront traités par le Gestionnaire de pilotes et risquent de ne pas produire les résultats attendus.
Chargement d’un fournisseur de magasin de clés
L’attribut de connexion SQL_COPT_SS_CEKEYSTOREPROVIDER
, s’il est défini, permet à une application cliente de charger une bibliothèque de fournisseurs. Les fournisseurs de magasins de clés que celle-ci contient deviennent ainsi utilisables.
SQLRETURN SQLSetConnectAttr( SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength);
Argument | Description |
---|---|
ConnectionHandle |
[Entrée] Handle de connexion. Il doit s’agir d’un handle de connexion valide, mais les fournisseurs chargés par le biais d’un handle de connexion sont accessibles à partir de n’importe quel autre handle dans le même processus. |
Attribute |
[Entrée] Attribut à définir : constante SQL_COPT_SS_CEKEYSTOREPROVIDER . |
ValuePtr |
[Entrée] Pointeur vers une chaîne de caractères se terminant par Null et spécifiant le nom de fichier de la bibliothèque de fournisseurs. Pour SQLSetConnectAttrA, cette valeur est une chaîne ANSI multioctets. Pour SQLSetConnectAttrW, cette valeur est une chaîne Unicode (wchar_t). |
StringLength |
[Entrée] Longueur de la chaîne ValuePtr, ou SQL_NTS. |
Le pilote tente de charger la bibliothèque identifiée par le paramètre ValuePtr à l’aide du mécanisme de chargement de bibliothèque dynamique défini par la plateforme (dlopen()
sur Linux et macOS, LoadLibrary()
sur Windows). Il ajoute tous les fournisseurs qui y sont définis à la liste des fournisseurs connus du pilote. Les erreurs suivantes peuvent se produire :
Error | Description |
---|---|
CE203 |
Le chargement de la bibliothèque dynamique a échoué. |
CE203 |
Le symbole exporté « CEKeyStoreProvider » est introuvable dans la bibliothèque. |
CE203 |
Un ou plusieurs fournisseurs dans la bibliothèque sont déjà chargés. |
SQLSetConnectAttr
retourne les valeurs d’erreur ou de réussite habituelles ; plus d’informations sont disponibles pour les erreurs éventuelles par le biais du mécanisme de diagnostic ODBC standard.
Notes
Le programmeur d’application doit s’assurer que les fournisseurs personnalisés soient chargés avant qu’une requête ayant besoin d’eux soit envoyée par le biais d’une connexion. L’échec de cette opération entraîne l’erreur :
Error | Description |
---|---|
CE200 |
Le fournisseur de magasins de clés %1 est introuvable. Assurez-vous que la bibliothèque du fournisseur de magasins de clés appropriée a été chargée. |
Notes
Les implémenteurs de fournisseurs de magasins de clés doivent éviter l’utilisation de MSSQL
dans le nom de leurs fournisseurs personnalisés. Ce terme est réservé exclusivement à une utilisation par Microsoft, et peut provoquer des conflits avec des fournisseurs intégrés ultérieurs. L’utilisation de ce terme dans le nom d’un fournisseur personnalisé peut générer un avertissement ODBC.
Récupération de la liste des fournisseurs chargés
L’obtention de cet attribut de connexion permet à une application cliente d’identifier les fournisseurs de magasins de clés actuellement chargés dans le pilote (y compris les fournisseurs intégrés). Ce processus peut uniquement être effectué après la connexion.
SQLRETURN SQLGetConnectAttr( SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER BufferLength, SQLINTEGER * StringLengthPtr);
Argument | Description |
---|---|
ConnectionHandle |
[Entrée] Handle de connexion. Il doit s’agir d’un handle de connexion valide, mais les fournisseurs chargés par le biais d’un handle de connexion sont accessibles à partir de n’importe quel autre handle dans le même processus. |
Attribute |
[Entrée] Attribut à récupérer : constante SQL_COPT_SS_CEKEYSTOREPROVIDER . |
ValuePtr |
[Sortie] Pointeur vers la mémoire dans laquelle retourner le nom du fournisseur chargé suivant. |
BufferLength |
[Entrée] Longueur de l’objet ValuePtr de la mémoire tampon. |
StringLengthPtr |
[Sortie] Pointeur vers une mémoire tampon dans laquelle retourner le nombre total d’octets (sans le caractère Null de fin) pouvant être retournés dans *ValuePtr. Si ValuePtr est un pointeur Null, aucune longueur n’est retournée. Si la valeur d’attribut est une chaîne de caractères et que le nombre d’octets pouvant être retournés est supérieur à BufferLength moins la longueur du caractère Null de fin, les données dans *ValuePtr sont tronquées à BufferLength moins la longueur du caractère Null de fin, et le caractère Null de fin est inséré par le pilote. |
Pour permettre la récupération de la liste complète, chaque opération Get retourne le nom du fournisseur actuel et incrémente un compteur interne. Une fois que ce compteur a atteint la fin de la liste, une chaîne vide ("") est retournée, et le compteur est réinitialisé. Les opérations Get suivantes reprennent ensuite à partir du début de la liste.
Communication avec les fournisseurs de magasins de clés
L’attribut de connexion SQL_COPT_SS_CEKEYSTOREDATA
permet à une application cliente de communiquer avec les fournisseurs de magasins de clés chargés pour configurer d’autres paramètres, des informations relatives aux clés, etc. La communication entre une application cliente et un fournisseur suit un protocole de demande-réponse simple, basé sur des requêtes Get et Set utilisant cet attribut de connexion. La communication est établie uniquement par l’application cliente.
Notes
Étant donné la nature de la réponse de CEKeyStoreProvider aux appels ODBC (SQLGet/SetConnectAttr), l’interface ODBC prend uniquement en charge la définition des données à la résolution du contexte de connexion.
L’application communique avec les fournisseurs de magasins de clés par le biais du pilote via la structure CEKeystoreData :
typedef struct CEKeystoreData {
wchar_t *name;
unsigned int dataSize;
char data[];
} CEKEYSTOREDATA;
Argument | Description |
---|---|
name |
[Entrée] En cas d’opération Set, nom du fournisseur auquel les données sont envoyées. Ignoré en cas d’opération Get. Chaîne à caractères larges se terminant par le caractère Null. |
dataSize |
[Entrée] Taille du tableau de données respectant la structure. |
data |
[InOut] En cas d’opération Set, données à envoyer au fournisseur. Ces données peuvent être arbitraires ; le pilote ne tente pas de les interpréter. En cas d’opération Get, mémoire tampon devant recevoir les données lues à partir du fournisseur. |
Écriture de données vers un fournisseur
Un appel SQLSetConnectAttr
utilisant l’attribut SQL_COPT_SS_CEKEYSTOREDATA
écrit un « paquet » de données dans le fournisseur de magasins de clés spécifié.
SQLRETURN SQLSetConnectAttr( SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength);
Argument | Description |
---|---|
ConnectionHandle |
[Entrée] Handle de connexion. Il doit s’agir d’un handle de connexion valide, mais les fournisseurs chargés par le biais d’un handle de connexion sont accessibles à partir de n’importe quel autre handle dans le même processus. |
Attribute |
[Entrée] Attribut à définir : constante SQL_COPT_SS_CEKEYSTOREDATA . |
ValuePtr |
[Entrée] Pointeur vers une structure CEKeystoreData. Le champ de nom de la structure identifie le fournisseur pour lequel les données sont prévues. |
StringLength |
[Entrée] Constante SQL_IS_POINTER |
D’autres informations détaillées sur les erreurs peuvent être obtenues par le biais de SQLGetDiacRec.
Notes
Le fournisseur peut utiliser le handle de connexion pour associer les données écrites à une connexion spécifique, s’il le souhaite. Cette fonctionnalité est utile pour implémenter la configuration par connexion. Il peut également ignorer le contexte de connexion et traiter les données de manière identique quelle que soit la connexion utilisée pour envoyer les données. Pour plus d’informations; consultez Association de contextes.
Lecture de données à partir d’un fournisseur
Un appel à SQLGetConnectAttr
à l’aide de l’attribut SQL_COPT_SS_CEKEYSTOREDATA
lit un « paquet » de données à partir du fournisseur dans lequel la dernière écriture a été effectuée. S’il n’y en a eu aucune, une erreur de séquence de fonction se produit. Nous encourageons les implémenteurs de fournisseurs de magasins de clés à prendre en charge les « écritures factices » de 0 octet comme moyen de sélectionner le fournisseur pour les opérations de lecture sans provoquer d’autres effets secondaires, si cela est pertinent.
SQLRETURN SQLGetConnectAttr( SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER BufferLength, SQLINTEGER * StringLengthPtr);
Argument | Description |
---|---|
ConnectionHandle |
[Entrée] Handle de connexion. Il doit s’agir d’un handle de connexion valide, mais les fournisseurs chargés par le biais d’un handle de connexion sont accessibles à partir de n’importe quel autre handle dans le même processus. |
Attribute |
[Entrée] Attribut à récupérer : constante SQL_COPT_SS_CEKEYSTOREDATA . |
ValuePtr |
[Sortie] Pointeur vers une structure CEKeystoreData dans laquelle les données lues à partir du fournisseur sont placées. |
BufferLength |
[Entrée] Constante SQL_IS_POINTER |
StringLengthPtr |
[Sortie] Pointeur vers une mémoire tampon dans laquelle retourner BufferLength. Si *ValuePtr est un pointeur Null, aucune longueur n’est retournée. |
L’appelant doit s’assurer qu’une mémoire tampon de longueur suffisante suivant la structure CEKEYSTOREDATA est allouée pour l’écriture par le fournisseur. Au retour, son champ dataSize est mis à jour avec la longueur réelle des données lues à partir du fournisseur. D’autres informations détaillées sur les erreurs peuvent être obtenues par le biais de SQLGetDiacRec.
Cette interface n’a aucune autre exigence quant au format des données transférées entre une application et un fournisseur de magasins de clés. Chaque fournisseur peut définir son propre format de data/protocole, en fonction de ses besoins.
Pour obtenir un exemple d’implémentation de votre propre fournisseur de magasin de clés, consultez Fournisseurs de magasins de clés personnalisés
Limitations du pilote ODBC lors de l’utilisation d’Always Encrypted
Opérations asynchrones
Le pilote ODBC autorise l’utilisation des opérations asynchrones avec Always Encrypted. Cependant, elles ont un impact sur le niveau de performance quand Always Encrypted est activé. L’appel à sys.sp_describe_parameter_encryption
pour déterminer les métadonnées de chiffrement pour l’instruction a un caractère bloquant, et obligera le pilote à attendre que le serveur retourne les métadonnées avant de retourner SQL_STILL_EXECUTING
.
Récupérer une partie des données avec SQLGetData
Avant la version 17 du pilote ODBC pour SQL Server, il n’est pas possible de récupérer une partie des colonnes binaires et des caractères chiffrés avec SQLGetData. Un seul appel de SQLGetData est possible, avec une mémoire tampon de taille suffisante pour contenir la totalité des données de la colonne.
Envoyer une partie des données avec SQLPutData
Avant ODBC Driver 17.3 for SQL Server, il n’est pas possible d’envoyer une partie des données à des fins de comparaison ou d’insertion avec SQLPutData. Un seul appel à SQLPutData est possible, avec une mémoire tampon contenant la totalité des données. Pour insérer des données de type long dans des colonnes chiffrées, utilisez l’API de copie en bloc, décrite dans la section suivante, avec un fichier de données d’entrée.
Colonnes money et smallmoney chiffrées
Les paramètres ne peuvent pas cibler les colonnes money ni smallmoney chiffrées, car il n’existe aucun type de données ODBC correspondant spécifiquement à ces types. Il en résulte des erreurs Operand Type Clash (conflit de type d’opérande).
Copie en bloc de colonnes chiffrées
Les fonctions de copie en bloc SQL et l’utilitaire bcp sont pris en charge avec Always Encrypted depuis la version 17 du pilote ODBC pour SQL Server. Le texte en clair (chiffré lors de l’insertion et déchiffré lors de la récupération) et le texte chiffré (transféré textuellement) peuvent être insérés et récupérés à l’aide des API de copie en bloc (bcp_*) et de l’utilitaire bcp.
Pour récupérer du texte chiffré au format varbinary(max) (par exemple, pour le chargement en masse dans une autre base de données), connectez-vous sans l’option
ColumnEncryption
(ou en lui donnant la valeurDisabled
) et effectuez une opération BCP OUT.Pour insérer et récupérer du texte clair et laisser le pilote effectuer en toute transparence le chiffrement et le déchiffrement, il suffit de donner la valeur
Enabled
àColumnEncryption
. Les fonctionnalités de l’API BCP restent inchangées par ailleurs.Pour insérer du texte chiffré au format varbinary(max), tel qu’il a été récupéré ci-dessus, par exemple, donnez la valeur TRUE à l’option
BCPMODIFYENCRYPTED
et effectuez une opération BCP IN. Pour que les données résultantes soient déchiffrées, la clé CEK de la colonne de destination doit être la même clé CEK que celle avec laquelle le texte chiffré a été obtenu à l’origine.
Si vous utilisez l’utilitaire bcp : pour contrôler le paramètre ColumnEncryption
, utilisez l’option -D et spécifiez un nom de source de données contenant la valeur souhaitée. Pour insérer du texte chiffré, veillez à ce que le paramètre ALLOW_ENCRYPTED_VALUE_MODIFICATIONS
de l’utilisateur soit activé.
Le tableau suivant fournit un résumé des actions en cas d’opération sur une colonne chiffrée :
ColumnEncryption |
Direction BCP | Description |
---|---|---|
Disabled |
OUT (vers le client) | Récupère le texte chiffré. Le type de données observé est varbinary(max) . |
Enabled |
OUT (vers le client) | Récupère le texte en clair. Le pilote déchiffre les données de colonne. |
Disabled |
IN (vers le serveur) | Insère le texte chiffré. Ce paramètre a pour but de déplacer de manière opaque des données chiffrées sans exiger leur déchiffrement. L’opération échoue si l’option ALLOW_ENCRYPTED_VALUE_MODIFICATIONS n’est pas définie sur l’utilisateur, ou si BCPMODIFYENCRYPTED n’est pas défini sur le handle de connexion. Pour plus d’informations, voir plus bas. |
Enabled |
IN (vers le serveur) | Insère le texte en clair. Le pilote chiffre les données de colonne. |
Option BCPMODIFYENCRYPTED
Pour empêcher l’altération des données, le serveur n’autorise en principe pas l’insertion de texte chiffré directement dans une colonne chiffrée : toute tentative échoue. Pour le chargement en bloc de données chiffrées avec l’API BCP toutefois, il est possible d’insérer directement du texte chiffré si l’option BCPMODIFYENCRYPTED
bcp_control a la valeur TRUE. Le risque d’altération des données chiffrées est ainsi réduit par rapport à l’option ALLOW_ENCRYPTED_VALUE_MODIFICATIONS
, définie sur le compte d’utilisateur. Néanmoins, les clés doivent correspondre aux données. Il est judicieux d’effectuer quelques vérifications en lecture seule des données insérées après l’insertion en bloc et avant toute utilisation ultérieure.
Pour plus d’informations, consultez Migrer des données sensibles protégées par Always Encrypted.
Synthèse de l’API Always Encrypted
Mots clés de chaîne de connexion
Nom | Description |
---|---|
ColumnEncryption |
Les valeurs acceptées sont Enabled /Disabled .Enabled : active la fonctionnalité Always Encrypted pour la connexion.Disabled : désactive la fonctionnalité Always Encrypted pour la connexion.attestation protocol, attestation URL (version 17.4 et versions ultérieures) : activent Always Encrypted avec enclave sécurisée en utilisant le protocole d’attestation et l’URL d’attestation spécifiés. Par défaut, il s’agit de Disabled . |
KeyStoreAuthentication |
Valeurs valides : KeyVaultPassword , KeyVaultClientSecret , KeyVaultInteractive et KeyVaultManagedIdentity . |
KeyStorePrincipalId |
En présence de KeyStoreAuthentication = KeyVaultPassword , définissez cette valeur sur un nom d’utilisateur Microsoft Entra valide. En présence de KeyStoreAuthetication = KeyVaultClientSecret , définissez cette valeur sur un ID client d’application Microsoft Entra validerEn présence de KeyStoreAuthetication = KeyVaultManagedIdentity , définissez cette valeur sur l’ID objet d’une identité managée affectée par l’utilisateur. Si aucune valeur n’est définie, l’identité managée affectée par le système est utilisée. |
KeyStoreSecret |
Quand KeyStoreAuthentication = KeyVaultPassword , affectez à cette valeur le mot de passe du nom d’utilisateur correspondant. En présence de KeyStoreAuthentication = KeyVaultClientSecret , affectez à cette valeur le secret d’application associé à un ID client d’application Microsoft Entra valide. |
Attributs de connexion
Nom | Type | Description |
---|---|---|
SQL_COPT_SS_COLUMN_ENCRYPTION |
Avant la connexion | SQL_COLUMN_ENCRYPTION_DISABLE (0) - désactiver Always EncryptedSQL_COLUMN_ENCRYPTION_ENABLE (1) : activer Always Encrypted.pointeur vers la chaîne *attestation protocol*,*attestation URL* (version 17.4 et versions ultérieures) : activer avec l’enclave sécurisée. |
SQL_COPT_SS_CEKEYSTOREPROVIDER |
Après la connexion | [Set] - Tenter de charger CEKeystoreProvider [Get] - Retourner un nom CEKeystoreProvider |
SQL_COPT_SS_CEKEYSTOREDATA |
Après la connexion | [Set] - Écrire les données dans CEKeystoreProvider [Get] - Lire les données à partir de CEKeystoreProvider |
SQL_COPT_SS_CEKCACHETTL |
Après la connexion | [Set] - Définir la durée de vie du cache de clés CEK [Get] - Obtenir la durée de vie actuelle du cache de clés CEK |
SQL_COPT_SS_TRUSTEDCMKPATHS |
Après la connexion | [Set] - Définir le pointeur des chemins de clés CMK approuvés [Get] - Obtenir le pointeur actuel des chemins de clés CMK approuvés |
Attributs d’instruction
Nom | Description |
---|---|
SQL_SOPT_SS_COLUMN_ENCRYPTION |
SQL_CE_DISABLED (0) - Always Encrypted est désactivé pour l’instructionSQL_CE_RESULTSETONLY (1) : déchiffrement uniquement. Les jeux de résultats et les valeurs renvoyées sont déchiffrés, et les paramètres ne sont pas chiffrésSQL_CE_ENABLED (3) : Always Encrypted est activé et utilisé pour les paramètres et les résultats. |
Champs de descripteur
Champ IPD | Taille/Type | Valeur par défaut | Description |
---|---|---|---|
SQL_CA_SS_FORCE_ENCRYPT (1236) |
WORD (deux octets) | 0 | Quand ce champ a la valeur 0 (valeur par défaut) : la décision de chiffrer ce paramètre est déterminé par la disponibilité des métadonnées de chiffrement. Quand ce champ a une valeur différente de zéro : si des métadonnées de chiffrement sont disponibles pour ce paramètre, il est chiffré. Sinon, la requête échoue avec l’erreur [CE300] [Microsoft][ODBC Driver 17 for SQL Server]Le chiffrement obligatoire a été spécifié pour un paramètre, mais aucune métadonnée de chiffrement n’a été fournie par le serveur. |
Options bcp_control
Nom d’option | Valeur par défaut | Description |
---|---|---|
BCPMODIFYENCRYPTED (21) |
FALSE | Quand la valeur est TRUE, autorise l’insertion de valeurs varbinary(max) dans une colonne chiffrée. Quand la valeur est FALSE, empêche l’insertion, sauf si les métadonnées de chiffrement et le type correct sont fournis. |
Dépannage
Si vous rencontrez des difficultés avec Always Encrypted, commencez par vérifier les points suivants :
La clé CEK qui chiffre la colonne souhaitée est présente et accessible sur le serveur.
La clé CMK qui chiffre le clé CEK comporte des métadonnées accessibles sur le serveur et est également accessible à partir du client.
ColumnEncryption
est activé dans le nom de source de données, la chaîne de connexion ou l’attribut de connexion et, si vous utilisez l’enclave sécurisée, est au bon format.
Par ailleurs, si vous utilisez l’enclave sécurisée, les défaillances d’attestation permettent d’identifier l’étape du processus d’attestation où la défaillance s’est produite, selon le tableau suivant :
Étape | Description |
---|---|
0-99 | Réponse d’attestation non valide ou erreur lors de la vérification de la signature. |
100-199 | Erreur lors de la récupération des certificats à partir de l’URL d’attestation. Vérifiez que <attestation URL>/v2.0/signingCertificates est valide et accessible. |
200-299 | Format inattendu ou incorrect de l’identité de l’enclave. |
300-399 | Erreur lors de l’établissement d’un canal sécurisé avec l’enclave. |