Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Lorsqu’une application utilisateur demande des données d’objets sur le système via un fournisseur WMI, l’emprunt d’identité signifie que le fournisseur présente les informations d’identification qui représentent le niveau de sécurité du client plutôt que celui du fournisseur. L’emprunt d’identité empêche un client d’obtenir un accès non autorisé aux informations sur le système.
Les sections suivantes sont décrites dans cette rubrique :
- Inscription d’un fournisseur pour l’usurpation d’identité
- Définition des niveaux d’usurpation d'identité au sein d’un fournisseur
- Gestion des niveaux de sécurité dans un fournisseur
- Gestion des messages refusés d’accès dans un fournisseur
- Rapports d’instances partielles
- Rapportage des énumérations partielles
- Débogage de votre code refusé d’accès
- rubriques connexes
WMI s’exécute généralement en tant que service d’administration à un niveau de sécurité élevé, à l’aide du contexte de sécurité LocalServer. L’utilisation d’un service d’administration donne à WMI les moyens d’accéder aux informations privilégiées. Lors de l’appel d’un fournisseur pour obtenir des informations, WMI transmet son IDENTIFICATEUR de sécurité (SID) au fournisseur, ce qui permet au fournisseur d’accéder aux informations au même niveau de sécurité élevé.
Pendant le processus de lancement de l’application WMI, le système d’exploitation Windows donne à l’application WMI le contexte de sécurité de l’utilisateur qui a commencé le processus. Le contexte de sécurité de l’utilisateur est généralement un niveau de sécurité inférieur à LocalServer. L’utilisateur peut donc ne pas avoir l’autorisation d’accéder à toutes les informations disponibles pour WMI. Lorsque l’application utilisateur demande des informations dynamiques, WMI transmet le SID de l’utilisateur au fournisseur correspondant. S’il est écrit de manière appropriée, le fournisseur tente d’accéder aux informations avec le SID utilisateur, plutôt que le SID du fournisseur.
Pour que le fournisseur se fasse passer correctement pour l’application cliente, l’application cliente et le fournisseur doivent remplir les critères suivants :
- L’application cliente doit appeler WMI avec un niveau de sécurité de connexion COM de RPC_C_IMP_LEVEL_IMPERSONATE ou de RPC_C_IMP_LEVEL_DELEGATE. Pour plus d’informations, consultez Maintenance de la sécurité WMI.
- Le fournisseur doit s’inscrire auprès de WMI en tant que fournisseur d’usurpation d’identité. Pour plus d’informations, consultez Enregistrer un fournisseur pour l’usurpation d’identité.
- Le fournisseur doit passer au niveau de sécurité de l’application cliente avant d’accéder aux informations privilégiées. Pour plus d’informations, consultez Définition des niveaux d’emprunt d’identité au sein d’un fournisseur.
- Le fournisseur doit gérer correctement les conditions d’erreur si l’accès à ces informations est refusé. Pour plus d’informations, consultez Gestion des messages refusés d’accès dans un fournisseur.
Enregistrement d'un fournisseur pour l'usurpation d'identité
WMI transmet uniquement le SID d’une application client aux fournisseurs enregistrés en tant que fournisseurs d’emprunt d’identité. Activer un fournisseur pour effectuer l’usurpation d’identité nécessite de modifier le processus d’enregistrement du fournisseur.
La procédure suivante décrit comment enregistrer un fournisseur pour l’usurpation d'identité. La procédure suppose que vous comprenez déjà le processus d’inscription. Pour plus d’informations sur le processus d’inscription, consultez Inscription d’un fournisseur.
Pour inscrire un fournisseur pour l’usurpation d’identité
Définissez la propriété ImpersonationLevel de la classe __Win32Provider qui représente votre fournisseur sur 1.
La propriété ImpersonationLevel indique si le fournisseur de service prend en charge l’emprunt d’identité ou non. Définir ImpersonationLevel sur 0 indique que le fournisseur n’emprunte pas l’identité du client et effectue toutes les opérations demandées dans le même contexte utilisateur que WMI. Définir ImpersonationLevel à 1 indique que le fournisseur utilise des appels d'usurpation d'identité pour vérifier les opérations effectuées au nom du client.
Définissez la propriété PerUserInitialization de la même classe __Win32Provider sur TRUE.
Remarque
Si vous inscrivez un fournisseur avec la propriété __Win32ProviderInitializeAsAdminFirst définie sur TRUE, le fournisseur utilise le jeton de sécurité de thread de l'administration uniquement pendant la phase d’initialisation. Si un appel à CoImpersonateClient n’échoue pas, le fournisseur utilise le contexte de sécurité de WMI et non du client.
L’exemple de code suivant montre comment enregistrer un fournisseur pour l’usurpation d'identité.
instance of __Win32Provider
{
CLSID = "{FD4F53E0-65DC-11d1-AB64-00C04FD9159E}";
ImpersonationLevel = 1;
Name = "MS_NT_EVENTLOG_PROVIDER";
PerUserInitialization = TRUE;
};
Définition des niveaux d’usurpation d’identité au sein d’un fournisseur
Si vous enregistrez un fournisseur à la classe __Win32Provider, avec la propriété ImpersonationLevel définie sur 1, alors WMI appelle votre fournisseur pour simuler l'identité de différents clients. Pour gérer ces appels, utilisez les fonctions COM CoImpersonateClient et CoRevertToSelf dans votre implémentation de l’interface IWbemServices .
La fonction CoImpersonateClient permet à un serveur d’emprunter l’identité du client qui a effectué l’appel. En plaçant un appel à CoImpersonateClient dans votre implémentation d’IWbemServices, vous autorisez votre fournisseur à définir le jeton de thread du fournisseur pour qu’il corresponde au jeton de thread du client, et donc emprunter l’identité du client. Si vous n’appelez pas CoImpersonateClient, votre fournisseur exécute du code au niveau administrateur de la sécurité, créant ainsi une vulnérabilité de sécurité potentielle. Si votre fournisseur doit temporairement agir en tant qu’administrateur ou effectuer la vérification d’accès manuellement, appelez CoRevertToSelf.
Contrairement à CoImpersonateClient, CoRevertToSelf est une fonction COM qui gère les niveaux d’emprunt d’identité de thread. Dans ce cas, CoRevertToSelf modifie le niveau d'emprunt d'identité en le ramenant au paramètre d'emprunt d'identité d'origine. En général, le fournisseur est initialement un administrateur et alterne entre CoImpersonateClient et CoRevertToSelf selon qu’il effectue un appel qui représente l’appelant ou ses propres appels. Il incombe au fournisseur de passer ces appels correctement afin de ne pas exposer un trou de sécurité à l’utilisateur final. Par exemple, le fournisseur doit appeler uniquement des fonctions Windows natives dans la séquence de code empruntée.
Remarque
L’objectif de CoImpersonateClient et coRevertToSelf est de définir la sécurité d’un fournisseur. Si vous constatez que votre usurpation d'identité a échoué, vous devez retourner un code de fin approprié à WMI via IWbemObjectSink::SetStatus. Pour plus d’informations, consultez Gestion des messages refusés d’accès dans un fournisseur.
Gestion des niveaux de sécurité dans un fournisseur
Les fournisseurs ne peuvent pas appeler CoImpersonateClient une seule fois dans une implémentation d’IWbemServices et supposer que les informations d’identification utilisées pour l'emprunt d'identité restent en place pour toute la durée de vie du fournisseur. Au lieu de cela, appelez CoImpersonateClient plusieurs fois au cours d’une implémentation pour empêcher WMI de modifier les informations d’identification.
La principale préoccupation de la définition de l’emprunt d’identité pour un fournisseur est la réentrance. Dans ce contexte, la réentrance est lorsqu’un fournisseur effectue un appel à WMI pour obtenir des informations et attend que WMI revient au fournisseur. En substance, le thread d’exécution quitte le code du fournisseur pour y revenir plus tard. La réentrée fait partie de la conception de COM et n’est généralement pas une source de préoccupation. Toutefois, lorsque le thread d’exécution entre dans WMI, le thread adopte les niveaux d’emprunt d’identité de WMI. Lorsque le thread revient chez le fournisseur, vous devez réinitialiser les niveaux d'emprunt d'identité avec un autre appel à CoImpersonateClient.
Pour vous protéger contre les failles de sécurité chez votre fournisseur, vous devez effectuer des appels réentrant dans WMI uniquement lors de l'usurpation d’identité du client. Autrement dit, les appels à WMI doivent être effectués après avoir appelé CoImpersonateClient et avant d’appeler CoRevertToSelf. Étant donné que CoRevertToSelf provoque l'emprunt d'identité à être défini au niveau utilisateur sous lequel WMI fonctionne, généralement LocalSystem, les appels rentrants à WMI après avoir appelé CoRevertToSelf pourraient donner à l'utilisateur, et à tous les fournisseurs appelés, beaucoup plus de capacités qu'ils ne devraient pas avoir.
Remarque
Si vous appelez une fonction système ou une autre méthode d’interface, le contexte d’appel n’est pas garanti pour être conservé.
Gestion des messages refusés d’accès dans un fournisseur
La plupart des messages d’erreur Accès refusé s’affichent lorsqu’un client demande une classe ou des informations auxquelles il n’a pas accès. Si le fournisseur retourne un message d’erreur Accès refusé à WMI et que WMI le transmet au client, le client peut déduire que les informations existent. Dans certaines situations, il peut s’agir d’une violation de la sécurité. Par conséquent, votre fournisseur ne doit pas propager le message au client. Au lieu de cela, l’ensemble de classes que le fournisseur aurait fourni ne doit pas être exposé. De même, un fournisseur d’instances dynamiques doit appeler la source de données sous-jacente pour déterminer comment gérer les messages refusés d’accès. Il incombe au fournisseur de répliquer cette philosophie dans l’environnement WMI. Pour plus d’informations, consultez Rapports d’instances partielles et Rapports d’énumérations partielles.
Lorsque vous déterminez comment votre fournisseur doit gérer les messages refusés d’accès, vous devez écrire et déboguer votre code. Pendant le débogage, il est souvent pratique de distinguer entre un refus dû à une faible capacité d'usurpation d'identité et un refus dû à une erreur dans votre code. Vous pouvez utiliser un test simple dans votre code pour déterminer la différence. Pour plus d’informations, consultez Débogage de votre code refusé d’accès.
Rapports d’instances partielles
Une occurrence courante d’un message accès refusé est lorsque WMI ne peut pas fournir toutes les informations pour remplir une instance. Par exemple, un client peut avoir l’autorité d’afficher un objet disque dur, mais il peut ne pas avoir l’autorité de voir la quantité d’espace disponible sur le disque dur lui-même. Votre fournisseur doit déterminer comment gérer une situation lorsque le fournisseur ne peut pas remplir complètement une instance avec des propriétés en raison d’une violation d’accès.
WMI ne nécessite pas de réponse unique aux clients qui ont un accès partiel à une instance. Au lieu de cela, WMI version 1.x permet au fournisseur l’une des options suivantes :
Échouez toute l’opération avec WBEM_E_ACCESS_DENIED et ne retournez aucune instance.
Retourne un objet d’erreur avec WBEM_E_ACCESS_DENIED, pour décrire la raison du déni.
Retourne toutes les propriétés disponibles et remplissez les propriétés non disponibles avec NULL.
Remarque
Assurez-vous que le fait de retourner WBEM_E_ACCESS_DENIED n'entraîne pas de faille de sécurité dans votre entreprise.
Rapports d’énumérations partielles
Une autre occurrence courante d’une violation d’accès est lorsque WMI ne peut pas retourner l’ensemble d’une énumération. Par exemple, un client peut avoir accès à l’affichage de tous les objets d’ordinateur de réseau local, mais n’a peut-être pas accès à l’affichage d’objets ordinateur en dehors de son domaine. Votre fournisseur doit déterminer comment gérer une situation quand une énumération ne peut pas être terminée en raison d’une violation d’accès.
Comme pour un fournisseur d’instances, WMI ne nécessite pas de réponse unique à une énumération partielle. Au lieu de cela, WMI version 1.x permet à un fournisseur l’une des options suivantes :
Retournez WBEM_S_NO_ERROR pour toutes les instances auxquelles le fournisseur peut accéder.
Si vous utilisez cette option, l’utilisateur ne sait pas que certaines instances n’ont pas été disponibles. Un certain nombre de fournisseurs, tels que ceux qui utilisent structured Query Language (SQL) avec une sécurité au niveau des lignes, retournent des résultats partiels réussis à l’aide du niveau de sécurité de l’appelant pour définir le jeu de résultats.
Échouez toute l’opération avec WBEM_E_ACCESS_DENIED et ne retournez aucune instance.
Le fournisseur peut éventuellement inclure un objet d’erreur qui décrit la situation au client. Notez que certains fournisseurs peuvent accéder en série à des sources de données et ne pas rencontrer de dénis tant que l’énumération n’est pas en partie parcourue.
Renvoyer toutes les instances accessibles, mais également renvoyer le code d’état non-error WBEM_S_ACCESS_DENIED.
Le fournisseur doit noter le déni pendant l’énumération et continuer à fournir des instances, en terminant avec le code d’état non-error. Le fournisseur peut également choisir de mettre fin à l’énumération au premier déni. La justification de cette option est que différents fournisseurs ont des paradigmes de récupération différents. Un fournisseur a peut-être déjà remis des instances avant de découvrir une violation d’accès. Certains fournisseurs peuvent choisir de continuer à fournir d’autres instances et d’autres peuvent souhaiter se terminer.
En raison de la structure de COM, vous ne pouvez pas marshaler d’informations pendant une erreur, à l’exception d’un objet d’erreur. Par conséquent, vous ne pouvez pas retourner à la fois les informations et un code d’erreur. Si vous choisissez de retourner des informations, vous devez utiliser un code d'état sans erreur à la place.
Débogage de votre code d'accès refusé
Certaines applications peuvent utiliser des niveaux d’emprunt d’identité inférieurs à RPC_C_IMP_LEVEL_IMPERSONATE. Dans ce cas, la plupart des appels d'usurpation d'identité effectués par le fournisseur pour l’application cliente échouent. Pour concevoir et implémenter un fournisseur, vous devez garder cette idée à l’esprit.
Par défaut, le seul autre niveau d’emprunt d’identité pouvant accéder à un fournisseur est RPC_C_IMP_LEVEL_IDENTIFY. Dans les cas où une application cliente utilise RPC_C_IMP_LEVEL_IDENTIFY, CoImpersonateClient ne retourne pas de code d’erreur. Au lieu de cela, le fournisseur emprunte l’identité du client à des fins d’identification uniquement. Par conséquent, la plupart des méthodes Windows appelées par le fournisseur retournent un message d’accès refusé. Cela est inoffensif dans la pratique, car les utilisateurs ne seront pas autorisés à faire quoi que ce soit inapproprié. Toutefois, il peut être utile durant le développement du prestataire de savoir si le client a réellement été usurpé ou non.
Le code nécessite les instructions #include et les références suivantes pour compiler correctement.
#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <wbemidl.h>
L’exemple de code suivant montre comment déterminer si un fournisseur a emprunté l’identité d’une application cliente.
DWORD dwImp = 0;
HANDLE hThreadTok;
DWORD dwBytesReturned;
BOOL bRes;
// You must call this before trying to open a thread token!
CoImpersonateClient();
bRes = OpenThreadToken(
GetCurrentThread(),
TOKEN_QUERY,
TRUE,
&hThreadTok
);
if (bRes == FALSE)
{
printf("Unable to read thread token (%d)\n", GetLastError());
return 0;
}
bRes = GetTokenInformation(
hThreadTok,
TokenImpersonationLevel,
&dwImp,
sizeof(DWORD),
&dwBytesReturned
);
if (!bRes)
{
printf("Unable to read impersonation level\n");
CloseHandle(hThreadTok);
return 0;
}
switch (dwImp)
{
case SecurityAnonymous:
printf("SecurityAnonymous\n");
break;
case SecurityIdentification:
printf("SecurityIdentification\n");
break;
case SecurityImpersonation:
printf("SecurityImpersonation\n");
break;
case SecurityDelegation:
printf("SecurityDelegation\n");
break;
default:
printf("Error. Unable to determine impersonation level\n");
break;
}
CloseHandle(hThreadTok);
Rubriques connexes