Share via


Durchführen eines Identitätswechsels für einen Client

Wenn eine Benutzeranwendung über einen WMI-Anbieter Daten von Objekten im System anfordert, bedeutet ein Identitätswechsel, dass der Anbieter Anmeldeinformationen vorlegt, die der Sicherheitsstufe des Clients und nicht der des Anbieters entsprechen. Der Identitätswechsel verhindert, dass ein Client unbefugten Zugriff auf Informationen im System erhält.

Dieses Thema umfasst die folgenden Abschnitte:

WMI wird in der Regel als administrativer Dienst mit einer hohen Sicherheitsstufe ausgeführt, wobei der Sicherheitskontext „LocalServer“ verwendet wird. Durch die Verwendung eines Verwaltungsdiensts kann WMI auf privilegierte Informationen zugreifen. Beim Aufruf eines Anbieters zur Abfrage von Informationen übergibt WMI seine Sicherheits-ID (SID) an den Anbieter, damit dieser mit derselben hohen Sicherheitsstufe auf die Informationen zugreifen kann.

Während des Startvorgangs der WMI-Anwendung weist das Windows-Betriebssystem der WMI-Anwendung den Sicherheitskontext des Benutzers bzw. der Benutzerin zu, der bzw. die den Prozess gestartet hat. Der Sicherheitskontext der Benutzer*innen hat in der Regel eine niedrigere Sicherheitsstufe als „LocalServer“, sodass das Benutzerkonto möglicherweise nicht die Berechtigung hat, auf alle für WMI verfügbaren Informationen zuzugreifen. Wenn die Benutzeranwendung dynamische Informationen anfordert, übergibt WMI die SID des Benutzers bzw. der Benutzerin an den betreffenden Anbieter. Sofern ordnungsgemäß geschrieben, versucht der Anbieter, mit der Benutzer-SID und nicht mit der Anbieter-SID auf die Informationen zuzugreifen.

Damit der Anbieter erfolgreich die Identität der Clientanwendung annehmen kann, müssen die Clientanwendung und der Anbieter die folgenden Kriterien erfüllen:

Registrieren eines Anbieters für den Identitätswechsel

WMI übergibt die SID einer Clientanwendung nur an Anbieter, die sich als Anbieter für den Identitätswechsel registriert haben. Damit ein Anbieter einen Identitätswechsel durchführen kann, müssen Sie den Prozess der Anbieterregistrierung ändern.

Im folgenden Verfahren wird beschrieben, wie Sie einen Anbieter für den Identitätswechsel registrieren. Bei diesem Verfahren wird davon ausgegangen, dass Sie den Registrierungsprozess bereits kennen. Weitere Informationen zum Registrierungsprozess finden Sie unter Registrieren eines Anbieters.

So registrieren Sie einen Anbieter für den Identitätswechsel

  1. Legen Sie die Eigenschaft ImpersonationLevel der Klasse __Win32Provider, die Ihren Anbieter repräsentiert, auf 1 fest.

    Die Eigenschaft ImpersonationLevel dokumentiert, ob der Anbieter einen Identitätswechsel unterstützt oder nicht. Wenn Sie ImpersonationLevel auf 0 festlegen, bedeutet dies, dass der Anbieter nicht die Identität des Clients annimmt und alle angeforderten Vorgänge im gleichen Benutzerkontext wie WMI ausführt. Wenn Sie ImpersonationLevel auf 1 festlegen, verwendet der Anbieter Identitätswechselaufrufe, um die im Namen des Clients ausgeführten Vorgänge zu überprüfen.

  2. Legen Sie die Eigenschaft PerUserInitialization derselben __Win32Provider-Klasse auf TRUE fest.

Hinweis

Wenn Sie einen Anbieter registrieren, bei dem die __Win32Provider-Eigenschaft InitializeAsAdminFirst auf TRUE festgelegt ist, dann verwendet der Anbieter das Threadsicherheitstoken der Verwaltungsebene nur während der Initialisierungsphase. Obwohl ein Aufruf von CoImpersonateClient nicht fehlschlägt, verwendet der Anbieter den Sicherheitskontext von WMI und nicht den des Clients.

 

Das folgende Codebeispiel zeigt, wie Sie einen Anbieter für den Identitätswechsel registrieren.

instance of __Win32Provider
{
    CLSID = "{FD4F53E0-65DC-11d1-AB64-00C04FD9159E}";
    ImpersonationLevel = 1;
    Name = "MS_NT_EVENTLOG_PROVIDER";
    PerUserInitialization = TRUE;
};

Festlegen von Identitätswechselebenen innerhalb eines Anbieters

Wenn Sie einen Anbieter registrieren, bei dem die Eigenschaft ImpersonationLevel der Klasse __Win32Provider auf 1 festgelegt ist, ruft WMI Ihren Anbieter auf, um Identitätswechsel für verschiedene Clients durchzuführen. Verwenden Sie zur Verarbeitung dieser Aufrufe die COM-Funktionen CoImpersonateClient und CoRevertToSelf in Ihrer Implementierung der IWbemServices-Schnittstelle.

Die Funktion CoImpersonateClient ermöglicht es einem Server, die Identität des aufrufenden Clients anzunehmen. Indem Sie einen Aufruf von CoImpersonateClient in Ihre Implementierung von IWbemServices einfügen, ermöglichen Sie es Ihrem Anbieter, das Threadtoken des Anbieters so festzulegen, dass es mit dem Threadtoken des Clients übereinstimmt. Dadurch kann der Anbieter die Identität des Clients annehmen. Wenn Sie CoImpersonateClient nicht aufrufen, führt Ihr Anbieter Code mit der Sicherheitsstufe eines Administrators aus, wodurch ein potenzielles Sicherheitsrisiko entsteht. Wenn Ihr Anbieter vorübergehend als Administrator agieren oder die Zugriffsprüfung manuell durchführen muss, rufen Sie CoRevertToSelf auf.

Im Gegensatz zu CoImpersonateClient ist CoRevertToSelf eine COM-Funktion, die Identitätswechsel von Threads handhabt. In diesem Fall ändert CoRevertToSelf die Identitätswechselebene zurück auf die ursprüngliche Einstellung für den Identitätswechsel. Im Allgemeinen handelt der Anbieter zunächst als Administrator und wechselt zwischen CoImpersonateClient und CoRevertToSelf, je nachdem, ob er einen Aufruf durchführt, der die aufrufende Funktion repräsentiert oder seine eigenen Aufrufe. Es liegt in der Verantwortung des Anbieters, diese Aufrufe korrekt zu platzieren, um die Endbenutzer*innen keinem Sicherheitsrisiko auszusetzen. Beispielsweise sollte der Anbieter innerhalb der Codesequenz für den Identitätswechsel nur native Windows-Funktionen aufrufen.

Hinweis

Der Zweck von CoImpersonateClient und CoRevertToSelf besteht darin, die Sicherheit für einen Anbieter festzulegen. Wenn Sie feststellen, dass Ihr Identitätswechsel fehlgeschlagen ist, sollten Sie über IWbemObjectSink::SetStatus einen entsprechenden Abschlusscode an WMI zurückgeben. Weitere Informationen finden Sie unter Behandeln von Zugriffsverweigerungsmeldungen in einem Anbieter.

 

Verwalten von Sicherheitsstufen in einem Anbieter

Anbieter können in einer Implementierung von IWbemServices nicht einmalig CoImpersonateClient aufrufen und davon ausgehen, dass die Anmeldeinformationen für den Identitätswechsel für die Lebensdauer des Anbieters bestehen bleiben. Rufen Sie daher im Verlauf einer Implementierung mehrmals CoImpersonateClient auf, um zu verhindern, dass WMI die Anmeldeinformationen ändert.

Das Hauptproblem beim Einrichten des Identitätswechsels für einen Anbieter ist die Wiedereintrittsfähigkeit. In diesem Zusammenhang bedeutet Wiedereintrittsfähigkeit, dass ein Anbieter per Aufruf Informationen von WMI anfordert und wartet, bis WMI den Anbieter erneut aufruft. Dies bedeutet, dass der Ausführungsthread den Anbietercode verlässt, um dann zu einem späteren Zeitpunkt wieder in den Code einzutreten. Der Wiedereintritt ist Bestandteil des COM-Designs und stellt im Allgemeinen kein Problem dar. Wenn der Ausführungsthread jedoch in WMI eintritt, übernimmt der Thread die Identitätswechselebenen von WMI. Wenn der Thread zum Anbieter zurückkehrt, müssen Sie die Identitätswechselebenen mit einem weiteren Aufruf von CoImpersonateClient zurücksetzen.

Um sich vor Sicherheitslücken in Ihrem Anbieter zu schützen, sollten Sie wiedereintrittsfähige WMI-Aufrufe nur ausführen, während Sie die Identität des Clients annehmen. Das heißt, die WMI-Aufrufe sollten nach dem Aufruf von CoImpersonateClient und vor dem Aufruf von CoRevertToSelf erfolgen. Da CoRevertToSelf bewirkt, dass der Identitätswechsel auf die Benutzerebene zurückgesetzt wird, mit der WMI ausgeführt wird (üblicherweise „LocalSystem“), könnten wiederholte Aufrufe von WMI nach dem Aufruf von CoRevertToSelf den Benutzer*innen und allen aufgerufenen Anbietern deutlich mehr Möglichkeiten geben, als sie haben sollten.

Hinweis

Wenn Sie eine Systemfunktion oder eine andere Schnittstellenmethode aufrufen, ist nicht garantiert, dass der Aufrufkontext erhalten bleibt.

 

Behandeln von Zugriffsverweigerungsmeldungen in einem Anbieter

Die meisten Fehlermeldungen des Typs „Zugriff verweigert“ werden ausgegeben, wenn ein Client eine Klasse oder Informationen anfordert, auf die er keinen Zugriff hat. Wenn der Anbieter eine Zugriffsverweigerungsmeldung an WMI zurückgibt und WMI diese an den Client weitergibt, kann der Client daraus schließen, dass die Informationen vorhanden sind. In einigen Situationen kann dies eine Sicherheitsverletzung darstellen. Deshalb sollte Ihr Anbieter die Meldung nicht an den Client weiterleiten. Stattdessen sollte der Satz von Klassen, die der Anbieter bereitgestellt hätte, nicht offengelegt werden. In ähnlicher Weise sollte ein dynamischer Instanzanbieter die zugrundeliegende Datenquelle aufrufen, um zu bestimmen, wie er mit Zugriffsverweigerungsmeldungen umgehen soll. Es liegt in der Verantwortung des Anbieters, dieses Konzept auf die WMI-Umgebung zu übertragen. Weitere Informationen finden Sie unter Melden partieller Instanzen und Melden partieller Enumerationen.

Wenn Sie festlegen, wie Ihr Anbieter Zugriffsverweigerungsmeldungen behandeln soll, müssen Sie Ihren Code schreiben und debuggen. Beim Debuggen ist es oftmals sinnvoll, zwischen einer Verweigerung aufgrund eines Identitätswechsels auf niedriger Ebene und einer Verweigerung aufgrund eines Fehlers im Code zu unterscheiden. Sie können diesen Unterschied durch einen einfachen Test in Ihrem Code ermitteln. Weitere Informationen finden Sie unter Debuggen Ihres Zugriffsverweigerungscodes.

Melden partieller Instanzen

Eine Zugriffsverweigerungsmeldung tritt häufig auf, wenn WMI nicht alle Informationen zum Auffüllen einer Instanz bereitstellen kann. So kann ein Client beispielsweise über die Berechtigung verfügen, ein Datenträgerobjekt anzuzeigen, aber nicht über die Berechtigung zur Anzeige des verfügbaren Speicherplatzes auf dem Datenträger selbst. Ihr Anbieter muss festlegen, wie er mit einer Situation umgehen soll, in der er eine Instanz aufgrund einer Zugriffsverletzung nicht vollständig mit Eigenschaften füllen kann.

WMI fordert keine einzelne Antwort für Clients, die nur teilweise Zugriff auf eine Instanz haben. Stattdessen bietet WMI-Version 1.x dem Anbieter folgende Optionen:

  • Der gesamte Vorgang wird mit WBEM_E_ACCESS_DENIED als fehlgeschlagen eingestuft, und es werden keine Instanzen zurückgegeben.

    Es wird ein Fehlerobjekt zusammen mit WBEM_E_ACCESS_DENIED zurückgegeben, um den Grund für die Verweigerung zu beschreiben.

  • Es werden alle verfügbaren Eigenschaften zurückgegeben, und nicht verfügbare Eigenschaften werden mit NULL gefüllt.

Hinweis

Stellen Sie sicher, dass die Rückgabe von WBEM_E_ACCESS_DENIED nicht zu einer Sicherheitslücke in Ihrem Unternehmen führt.

 

Melden partieller Enumerationen

Eine weitere häufige Ursache für eine Zugriffsverletzung liegt vor, wenn WMI eine Enumeration nicht vollständig zurückgeben kann. So kann ein Client beispielsweise Zugriff auf alle Computerobjekte des lokalen Netzwerks haben, aber nicht auf Computerobjekte außerhalb seiner Domäne. Ihr Anbieter muss festlegen, wie Situationen zu behandeln sind, in denen eine Enumeration aufgrund einer Zugriffsverletzung nicht abgeschlossen werden kann.

Wie bei einem Instanzanbieter fordert WMI keine einzelne Antwort für eine partielle Enumeration. Stattdessen bietet WMI-Version 1.x dem Anbieter folgende Optionen:

  • Für alle Instanzen, auf die der Anbieter zugreifen kann, wird WBEM_S_NO_ERROR zurückgegeben.

    Wenn Sie diese Option verwenden, ist für die Benutzer*innen nicht ersichtlich, dass einige Instanzen nicht verfügbar waren. Einige Anbieter – z. B. diejenigen, die SQL (Structured Query Language) mit Sicherheit auf Zeilenebene verwenden – geben erfolgreiche Teilergebnisse zurück und verwenden dabei die Sicherheitsstufe des Aufrufers, um das Resultset zu definieren.

  • Der gesamte Vorgang wird mit WBEM_E_ACCESS_DENIED als fehlgeschlagen eingestuft, und es werden keine Instanzen zurückgegeben.

    Der Anbieter kann optional ein Fehlerobjekt einschließen, das die Situation für den Client beschreibt. Beachten Sie, dass einige Anbieter möglicherweise seriell auf Datenquellen zugreifen und erst während der Enumeration auf Verweigerungen stoßen.

  • Es werden alle Instanzen zurückgegeben, auf die zugegriffen werden kann, aber auch der NO_ERROR-Statuscode WBEM_S_ACCESS_DENIED.

    Der Anbieter sollte die Verweigerung während der Enumeration zur Kenntnis nehmen, kann mit der Bereitstellung von Instanzen fortfahren und mit dem NO_ERROR-Statuscode abschließen. Der Anbieter hat außerdem die Möglichkeit, die Enumeration bei der ersten Verweigerung zu beenden. Die Rechtfertigung für diese Option ist, dass verschiedene Anbieter unterschiedliche Abrufparadigmen nutzen. Ein Anbieter hat möglicherweise bereits Instanzen bereitgestellt, bevor eine Zugriffsverletzung erkannt wird. Einige Anbieter möchten eventuell weitere Instanzen bereitstellen, andere wiederum möchten den Vorgang beenden.

Aufgrund der Struktur von COM können Sie bei einem Fehler mit Ausnahme eines Fehlerobjekts keine Informationen zurücksenden. Daher können Sie nicht sowohl Informationen als auch einen Fehlercode zurückgeben. Wenn Sie Informationen zurückgeben möchten, müssen Sie stattdessen einen NO_ERROR-Statuscode verwenden.

Debuggen Ihres Zugriffsverweigerungscodes

Einige Anwendungen verwenden möglicherweise Identitätswechselebenen, die niedriger sind als RPC_C_IMP_LEVEL_IMPERSONATE. In diesem Fall werden die meisten Identitätswechselaufrufe des Anbieters für die Clientanwendung fehlschlagen. Für eine erfolgreiche Entwicklung und Implementierung eines Anbieters müssen Sie dies im Hinterkopf behalten.

Standardmäßig ist die einzige weitere Identitätswechselebene, die auf einen Anbieter zugreifen kann, RPC_C_IMP_LEVEL_IDENTIFY. In Fällen, in denen eine Clientanwendung RPC_C_IMP_LEVEL_IDENTIFY verwendet, gibt CoImpersonateClient keinen Fehlercode zurück. Stattdessen nimmt der Anbieter die Identität des Clients nur zur Identifizierung an. Deshalb geben die meisten Windows-Methoden, die vom Anbieter aufgerufen werden, eine Zugriffsverweigerungsmeldung zurück. Dies ist in der Praxis harmlos, da die Benutzer*innen keine unerlaubten Aufgaben ausführen dürfen. Bei der Anbieterentwicklung kann es jedoch nützlich sein, zu wissen, ob für den Client tatsächlich ein Identitätswechsel stattgefunden hat oder nicht.

Der Code erfordert für eine ordnungsgemäße Kompilierung die folgenden Verweise und #include-Anweisungen.

#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <wbemidl.h>

Das folgende Codebeispiel zeigt, wie Sie feststellen können, ob ein Anbieter erfolgreich die Identität einer Clientanwendung angenommen hat.

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

Entwickeln eines WMI-Anbieters

Festlegen von Sicherheitsbeschreibungen für Namespaces

Schützen Ihres Anbieters