Dela via


Utge sig för att vara en klient

När ett användarprogram begär data från objekt i systemet via en WMI-provider innebär personifiering att providern presenterar autentiseringsuppgifter som representerar klientens säkerhetsnivå i stället för providerns. Personifiering hindrar en klient från att få obehörig åtkomst till information i systemet.

Följande avsnitt beskrivs i det här avsnittet:

WMI körs vanligtvis som en administrativ tjänst på hög säkerhetsnivå med hjälp av säkerhetskontexten LocalServer. Att använda en administrativ tjänst ger WMI möjlighet att komma åt privilegierad information. När du anropar en provider för information skickar WMI sin säkerhetsidentifierare (SID) till providern, vilket gör det möjligt för providern att komma åt information på samma höga säkerhetsnivå.

Under WMI-programmets startprocess ger Windows-operativsystemet WMI-programmet säkerhetskontexten för den användare som påbörjade processen. Säkerhetskontexten för användaren är vanligtvis en lägre säkerhetsnivå än LocalServer, så användaren kanske inte har behörighet att komma åt all information som är tillgänglig för WMI. När användarprogrammet ber om dynamisk information skickar WMI användarens SID till motsvarande provider. Om det skrivs på rätt sätt försöker providern komma åt information med användar-SID i stället för providerns SID.

För att providern ska kunna personifiera klientprogrammet måste klientprogrammet och providern uppfylla följande kriterier:

Registrera en tjänstleverantör för efterbildning

WMI skickar endast SID för en klientapplikation till providers som har registrerat sig som impersonationsleverantörer. Om du vill att en provider ska kunna utföra personifiering måste du ändra registreringsprocessen för providern.

Följande procedur beskriver hur du registrerar en leverantör för efterliknande. Proceduren förutsätter att du redan förstår registreringsprocessen. Mer information om registreringsprocessen finns i Registrera en provider.

Registrera en leverantör för imitering

  1. Ange egenskapen ImpersonationLevel för den __Win32Provider-klass som representerar providern till 1.

    Egenskapen ImpersonationLevel dokumenterar om providern stöder personidentifiering eller inte. Inställningen ImpersonationLevel till 0 anger att providern inte personifierar klienten och utför alla begärda åtgärder i samma användarkontext som WMI. Inställningen ImpersonationLevel till 1 anger att providern använder personifieringsanrop för att kontrollera åtgärder som utförs för klientens räkning.

  2. Ange egenskapen PerUserInitialization för samma __Win32Provider-klass till TRUE.

Notis

Om du registrerar en provider med egenskapen __Win32ProviderInitializeAsAdminFirst inställd på TRUEanvänder providern endast trådsäkerhetstoken på administrationsnivå under initieringsfasen. Även om ett anrop till CoImpersonateClient inte misslyckas använder providern säkerhetskontexten för WMI och inte klienten.

 

I följande kodexempel visas hur du registrerar en leverantör för imitering.

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

Ange personifieringsnivåer inom en provider

Om du registrerar en provider med __Win32Provider-klassegenskapen ImpersonationLevel inställd på 1, så anropar WMI din provider för att imitera olika klienter. Om du vill hantera dessa anrop ska du använda COM-funktionerna CoImpersonateClient och CoRevertToSelf i din implementering av IWbemServices-gränssnittet.

Med funktionen CoImpersonateClient kan en server personifiera klienten som gjorde anropet. Genom att anropa CoImpersonateClient i implementeringen av IWbemServiceslåter du providern ange att providerns trådtoken ska matcha klientens trådtoken och därmed personifiera klienten. Om du inte anropar CoImpersonateClientkör providern kod på administratörsnivå för säkerhet, vilket skapar en potentiell säkerhetsrisk. Om leverantören tillfälligt behöver agera som administratör eller utföra åtkomstkontrollen manuellt anropar du CoRevertToSelf.

Till skillnad från CoImpersonateClientär CoRevertToSelf en COM-funktion som hanterar trådimitationsnivåer. I det här fallet ändrar CoRevertToSelf personifieringsnivån tillbaka till den ursprungliga personifieringsinställningen. I allmänhet är providern initialt administratör och växlar mellan CoImpersonateClient och CoRevertToSelf beroende på om den gör ett anrop som representerar anroparen eller dess egna anrop. Det är leverantörens ansvar att placera dessa anrop korrekt för att inte exponera ett säkerhetshål för slutanvändaren. Providern bör till exempel bara anropa interna Windows-funktioner i den personifierade kodsekvensen.

Not

Syftet med CoImpersonateClient och CoRevertToSelf är att konfigurera säkerhet för en leverantör. Om du bedömer att personifieringen misslyckades bör du returnera en lämplig slutförandekod till WMI via IWbemObjectSink::SetStatus. Mer information finns i Hantering av nekade åtkomstmeddelanden i en leverantör.

 

Upprätthålla säkerhetsnivåer i en provider

Leverantörer kan inte anropa CoImpersonateClient en gång i en implementering av IWbemServices och förutsätter att personifieringsuppgifterna finns kvar under providerns varaktighet. Anropa i stället CoImpersonateClient flera gånger under implementeringen för att förhindra att WMI ändrar autentiseringsuppgifterna.

Det viktigaste problemet med att ange personifiering för en provider är återaktivering. I det här sammanhanget är återinträde när en leverantör (provider) anropar WMI för information och väntar tills WMI anropar tillbaka till leverantören. I huvudsak lämnar körningstråden providerkoden, bara för att ange koden igen vid ett senare tillfälle. Återförsök är en del av utformningen av COM och är i allmänhet inte ett problem. Men när körningstråden går in i WMI övertar tråden WMI:s personifieringsnivåer. När tråden återgår till providern måste du återställa personifieringsnivåerna med ett annat anrop till CoImpersonateClient.

För att skydda dig mot säkerhetshål i din leverantör bör du endast göra återinträdande anrop till WMI under tiden du imiterar klienten. Det vill säga anrop till WMI ska göras efter att du anropar CoImpersonateClient och innan du anropar CoRevertToSelf. Eftersom CoRevertToSelf gör att personifieringen ställs in på den användarnivå där WMI körs, vanligtvis LocalSystem, kan återkommande anrop till WMI efter att ha anropat CoRevertToSelf ge användaren, och alla leverantörer som anropas, mycket fler behörigheter än de borde ha.

Not

Om du anropar en systemfunktion eller en annan gränssnittsmetod garanteras inte anropskontexten att underhållas.

 

Hantera åtkomst nekad-meddelanden i en leverantör

De flesta felmeddelanden om nekad åtkomst visas när en klient begär en klass eller information som de inte har åtkomst till. Om providern returnerar ett felmeddelande om nekad åtkomst till WMI och WMI skickar detta till klienten kan klienten dra slutsatsen att informationen finns. I vissa situationer kan detta vara ett säkerhetsbrott. Därför bör providern inte sprida meddelandet till klienten. I stället ska den uppsättning klasser som providern skulle ha angett inte exponeras. På samma sätt bör en dynamisk instansprovider anropa den underliggande datakällan för att avgöra hur åtkomst nekad meddelanden ska hanteras. Det är providerns ansvar att replikera den filosofin till WMI-miljön. Mer information finns i Rapportering av Delvisa Instanser och Rapportering av Delvisa Enumereringar.

När du bestämmer hur leverantören ska hantera meddelanden om nekad åtkomst måste du skriva och felsöka koden. Vid felsökning är det ofta praktiskt att skilja mellan ett avslag på grund av låg efterhärmning och ett avslag på grund av ett fel i din kod. Du kan använda ett enkelt test i koden för att fastställa skillnaden. Mer information finns i Felsök din behörighetsnekad kod.

Rapportera partiella fall

En vanlig förekomst av ett meddelande om nekad åtkomst är när WMI inte kan ange all information för att fylla en instans. En klient kan till exempel ha behörighet att visa ett hårddiskobjekt, men kanske inte har behörighet att se hur mycket utrymme som är tillgängligt på själva hårddisken. Leverantören måste bestämma hur den ska hantera alla situationer när providern inte helt kan fylla en instans med egenskaper på grund av en åtkomstöverträdelse.

WMI kräver inte ett enda svar till klienter som har partiell åtkomst till en instans. I stället tillåter WMI version 1.x providern något av följande alternativ:

  • Misslyckas med hela åtgärden med WBEM_E_ACCESS_DENIED och returnera inga instanser.

    Returnera ett felobjekt tillsammans med WBEM_E_ACCESS_DENIEDför att beskriva orsaken till avslaget.

  • Returnera alla tillgängliga egenskaper och fyll i otillgängliga egenskaper med NULL-.

Notera

Se till att returnera WBEM_E_ACCESS_DENIED inte skapar ett säkerhetshål i ditt företag.

 

Rapportera partiella uppräkningar

En annan vanlig förekomst av åtkomstbrott är när WMI inte kan returnera alla objekt i en uppräkning. En klient kan till exempel ha åtkomst till att visa alla objekt på den lokala nätverksdatorn, men kanske inte har åtkomst till att visa datorobjekt utanför domänen. Leverantören måste bestämma hur man ska hantera en situation när en uppräkning inte kan slutföras på grund av en åtkomstöverträdelse.

Precis som med en instansprovider kräver WMI inte ett enda svar på en partiell uppräkning. I stället tillåter WMI version 1.x en provider något av följande alternativ:

  • Returnera WBEM_S_NO_ERROR för samtliga instanser som providern kan komma åt.

    Om du använder det här alternativet är användaren inte medveten om att vissa instanser inte var tillgängliga. Ett antal leverantörer, till exempel de som använder Structured Query Language (SQL) med säkerhet på radnivå, returnerar lyckade partiella resultat med hjälp av anroparens säkerhetsnivå för att definiera resultatuppsättningen.

  • Misslyckas hela operationen med WBEM_E_ACCESS_DENIED och returnerar inga instanser.

    Providern kan också inkludera ett felobjekt som beskriver situationen för klienten. Observera att vissa leverantörer kan komma åt datakällor seriellt och kanske inte stöter på avslag förrän under pågående uppräkning.

  • Returnera alla instanser som kan nås men även returnera statuskoden nonerror WBEM_S_ACCESS_DENIED.

    Providern bör notera avslaget under uppräkningen och kan fortsätta att tillhandahålla instanser och slutföra med statuskoden nonerror. Leverantören kan också välja att avsluta uppräkningen vid det första avslaget. Motiveringen för det här alternativet är att olika leverantörer har olika hämtningsparadigm. En leverantör kan redan ha levererat instanser innan en åtkomstöverträdelse upptäcktes. Vissa leverantörer kan välja att fortsätta tillhandahålla andra instanser och andra kanske vill avsluta.

På grund av com-strukturen kan du inte återställa någon information under ett fel förutom ett felobjekt. Därför kan du inte returnera både information och en felkod. Om du väljer att returnera information måste du använda statuskoden nonerror i stället.

Felsöka åtkomstnekad kod

Vissa program kan använda personifieringsnivåer som är lägre än RPC_C_IMP_LEVEL_IMPERSONATE. I det här fallet misslyckas de flesta personifieringsanrop som görs av providern för klientprogrammet. För att kunna utforma och implementera en provider måste du ha den här idén i åtanke.

Som standardinställning är den enda andra personifieringsnivån som kan komma åt en leverantör RPC_C_IMP_LEVEL_IDENTIFY. Om ett klientprogram använder RPC_C_IMP_LEVEL_IDENTIFYreturnerar CoImpersonateClient inte någon felkod. I stället personifierar providern endast klienten i identifieringssyfte. Därför returnerar de flesta Windows-metoder som anropas av providern ett meddelande om nekad åtkomst. Detta är ofarligt i praktiken, eftersom användarna inte kommer att tillåtas att göra något olämpligt. Det kan dock vara användbart under leverantörsutvecklingen att veta om klienten verkligen har imiterats eller inte.

Koden kräver följande referenser och #include-instruktioner för att kompilera korrekt.

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

I följande kodexempel visas hur du avgör om en provider har personifierat ett klientprogram.

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

Utveckla en WMI-leverantör

Konfigurera namnrymdssäkerhetsbeskrivningar

Skydda din provider