Udostępnij przez


Uruchamianie aplikacji AppContainer

W tym artykule opisano kroki niezbędne do uruchomienia aplikacji AppContainer lub Mniej uprzywilejowanej aplikacjiContainer, w tym odpowiednich przykładów kodu. AppContainers to funkcja zabezpieczeń wprowadzona w systemie Windows 8 w celu zwiększenia izolacji i kontroli procesów aplikacji. Zapewniają one środowisko w trybie piaskownicy dla aplikacji, ograniczając możliwość uzyskiwania dostępu do zasobów systemu lub innych użytkowników, a także danych użytkowników, chyba że są jawnie dozwolone. AppContainers korzystają z istniejących mechanizmów zabezpieczeń systemu Windows, takich jak identyfikatory zabezpieczeń (SID), tokeny i deskryptora zabezpieczeń uznaniowa lista kontroli dostępu (DACL), aby wymusić te ograniczenia.

Terminologia

W poniższej tabeli zdefiniowano terminy i pojęcia, do których odwołuje się ten artykuł.

Termin Description
Tożsamość pakietu Tożsamość pakietu jest konstrukcją logiczną, unikatowo identyfikującą pakiet. Aby uzyskać więcej informacji, zobacz Omówienie tożsamości pakietu w aplikacjach systemu Windows.
Identyfikator zabezpieczeń (SID) Identyfikator SID służy do jednoznacznego identyfikowania podmiotu zabezpieczeń lub grupy zabezpieczeń. Podmioty zabezpieczeń mogą reprezentować dowolną jednostkę, którą system operacyjny może uwierzytelnić. Przykładem może być konto użytkownika, konto komputera lub wątek lub proces, który jest uruchamiany w kontekście zabezpieczeń konta użytkownika lub komputera. Aby uzyskać więcej informacji, zobacz Identyfikatory zabezpieczeń
Identyfikatory SID możliwości Identyfikatory SID zdolności służą jako unikatowe i niezmienne identyfikatory możliwości. Funkcja reprezentuje nieodwracalny token urzędu, który przyznaje aplikacji dostęp do zasobów (na przykład dokumenty, kamery i lokalizacje). Aby uzyskać więcej informacji, zobacz Deklaracje możliwości aplikacji
Uznaniowa lista kontroli dostępu (DACL) Lista identyfikująca użytkowników i grupy, którzy mogą wykonywać różne operacje na obiekcie. Aby uzyskać więcej informacji, zobacz Składniki deskryptora zabezpieczeń.
Mniej uprzywilejowane appContainers (LPAC) Typ aplikacji AppContainer, który jest bardziej izolowany niż zwykły appContainer. Wymaga to jawnych deklaracji możliwości uzyskiwania dostępu do zasobów, które są dostępne dla aplikacji AppContainers.

Omówienie aplikacji AppContainer

Gdy aplikacja działa jako aplikacja AppContainer, jej token dostępu zawiera unikatową tożsamość pakietu aplikacji (identyfikator SID pakietu) i co najmniej jeden identyfikator SID funkcji. W przypadku aplikacji AppContainers funkcje są używane w celu zapewnienia, że aplikacje AppContainers mogą działać z najniższymi uprawnieniami i w razie potrzeby mają dostęp tylko do potencjalnie poufnych zasobów. Na przykład bez możliwości sieci aplikacja AppContainer nie może uzyskać dostępu do sieci, bez możliwości kamery internetowej nie może uzyskać dostępu do aparatu fotograficznego. Identyfikatory SID aplikacji AppContainer (identyfikatory SID pakietu i możliwości) są oddzielone od tradycyjnych identyfikatorów SID użytkowników i grup z obydwoma częściami tokenu wymagane do udzielenia dostępu do chronionego zasobu za pośrednictwem listy kontroli dostępu (DACL) obiektu. Ten model z dwoma jednostkami gwarantuje, że dostęp do poufnych zasobów jest ściśle kontrolowany i może być zarządzany niezależnie dla różnych aplikacji. Gwarantuje to również, że usługi AppContainers muszą mieć jawnie przyznany dostęp do danego zasobu. Ponadto dozwolony dostęp jest skrzyżowaniem tego, który jest przyznany przez identyfikatory SID użytkownika/grupy i identyfikatory SID appContainer, więc jeśli użytkownik ma pełny dostęp, ale aplikacja AppContainer ma tylko dostęp do odczytu, appContainer może mieć tylko dostęp do odczytu. Podobnie, jeśli użytkownik ma dostęp do odczytu i wykonywania, ale aplikacja AppContainer ma pełny dostęp do aplikacji AppContainer, można udzielić dostępu tylko do odczytu i wykonywania.

Aplikacje AppContainers działają z niskim poziomem integralności (IL), co dodatkowo ogranicza możliwość interakcji z obiektami o wyższej integralności w systemie. Jeśli jednak zasób ma obowiązkową etykietę średniej liczby IL lub niższej, a lista DACL udziela dostępu do aplikacji AppContainer (za pośrednictwem identyfikatora SID pakietu lub identyfikatora SID możliwości), aplikacja AppContainer może odczytywać, zapisywać lub wykonywać w zależności od dostępu przyznanego obu podmiotom zabezpieczeń w daCL. Takie podejście zapewnia zarówno elastyczność, jak i zabezpieczenia, umożliwiając dostęp do niezbędnych zasobów przy jednoczesnym ograniczeniu potencjalnie szkodliwych akcji z niezaufanych lub naruszonych aplikacji.

Aplikacje AppContainers są odizolowane od uzyskiwania dostępu do procesów i okien należących do innych aplikacji, a także z urządzeń, plików/katalogów, kluczy rejestru, sieci i poświadczeń. W związku z tym zapewniają one mechanizm bezpiecznego analizowania niezaufanych danych w trybie piaskownicy potencjalnych ryzykownych operacji, takich jak analizowanie niezaufanych danych.

Zwykłe aplikacje AppContainers otrzymują dostęp do niektórych plików systemowych/katalogów, typowych kluczy rejestru i obiektów COM, jednak LPAC potrzebuje określonych możliwości dostępu do zasobów, do których mogą uzyskiwać zwykłe aplikacje AppContainers. Mniej uprzywilejowane appContainers (LPAC) są jeszcze bardziej izolowane niż zwykłe appContainers i wymagają dalszych możliwości, aby uzyskać dostęp do zasobów, do których zwykłych aplikacji AppContainers już mają dostęp, takich jak rejestr, pliki i inne. Na przykład LPAC nie może otworzyć żadnych kluczy w rejestrze, chyba że ma funkcję registryRead i nie może używać modelu COM, chyba że ma możliwość lpacCom .

Uruchamianie aplikacji AppContainer

Jak wspomniano wcześniej, usługa AppContainers ma unikatowy identyfikator SID pakietu, który zapewnia ochronę własnych zasobów przed innymi aplikacjami. Identyfikator SID pakietu pochodzi z nazwy ciągu (moniker) dla danej aplikacji AppContainer. W przypadku aplikacjiContainers zduplikowanych za pośrednictwem manifestu AppX jest to nazwa rodziny pakietów (PFN), ale w przypadku aplikacji uruchamiającej sam proces AppContainer aplikacja musi określić nazwę (moniker), która chce nadać aplikacji AppContainer.

Uruchomienie aplikacji AppContainer obejmuje kilka kroków. Konieczne jest określenie niezbędnych możliwości udzielenia, należy utworzyć profil dla aplikacji AppContainer, aby istniała lokalizacja, w której aplikacja AppContainer może tworzyć/odczytywać/zapisywać pliki, przetwarzać i atrybuty wątku, aby poinformować system Windows, że musi utworzyć aplikację AppContainer.

Konstruowanie możliwości

Aplikacja AppContainer (lub LPAC) może wymagać możliwości uzyskiwania dostępu do różnych zasobów, takich jak sieć, lokalizacja lub w przypadku rejestru lub obiektu COM LPAC. Konstruowanie możliwości można osiągnąć za pomocą interfejsu API DeriveCapabilitySidsFromName , chociaż lepiej jest opakowować ten interfejs API w funkcji pomocniczej, takiej jak GetCapabilitySidFromName pokazany w poniższym przykładowym kodzie, ponieważ identyfikatory SID grupy są używane tylko dla usług, a interfejs API zwraca tylko jedną funkcję.

BOOL GetCapabilitySidFromName( 
    PCWSTR CapabilityName, 
    PSID* CapabilitySid) 
{ 
    PSID* CapabilitySids; 
    DWORD CapabilitySidCount; 
    PSID* GroupSids; 
    DWORD GroupSidCount; 

    *CapabilitySid = NULL; 

    if (DeriveCapabilitySidsFromName(CapabilityName, &GroupSids, &GroupSidCount, & CapabilitySids, &CapabilitySidCount)) 
    { 
        LocalFree(GroupSids[0]); 
        LocalFree(GroupSids); 

        *CapabilitySid = CapabilitySids[0]; 
        LocalFree(CapabilitySids); 
        return TRUE; 

    }

    return FALSE; 
} 

Poniższy przykładowy kod demonstruje użycie funkcji pomocnika GetCapabilitySidFromName zdefiniowanej w poprzednim przykładzie w celu skonstruowania funkcji InternetClient i lokalizacji .

BOOL BuildAppContainerCapabilities( 
    PSID_AND_ATTRIBUTES* Capabilities, 
    DWORD* NumberOfCapabilities 
) 
{
    DWORD CapabilityCount; 
    PSID CapabilitySids[2]; 
    PSID_AND_ATTRIBUTES LocalCapabilities; 

    *Capabilities = NULL; 
    *NumberOfCapabilities = 0; 

    CapabilityCount = 0; 

    if (GetCapabilitySidFromName(L"internetClient", &CapabilitySids[CapabilityCount++]) == FALSE) 
    { 
        return FALSE; 
    } 

    if (GetCapabilitySidFromName(L"location", &CapabilitySids[CapabilityCount++]) == FALSE) 
    { 
        for (DWORD i = 0; i < CapabilityCount; ++i) 
        { 
            LocalFree(CapabilitySids[i]); 
        } 

        return FALSE; 
    } 

    LocalCapabilities =  
        (PSID_AND_ATTRIBUTES)HeapAlloc(GetProcessHeap(), 
        0, 
        CapabilityCount * sizeof(SID_AND_ATTRIBUTES)); 

    if (LocalCapabilities != NULL) 
    { 
        for (DWORD i = 0; i < CapabilityCount; ++i) 
        { 
            LocalCapabilities[i].Sid = CapabilitySids[i]; 
            LocalCapabilities[i].Attributes = SE_GROUP_ENABLED; 
        } 
    }
    else 
    { 
        for (DWORD i = 0; i < CapabilityCount; ++i) 
        {
            LocalFree(CapabilitySids[i]); 
        } 

        return FALSE; 
    } 

    *Capabilities = LocalCapabilities; 
    *NumberOfCapabilities = CapabilityCount; 

    return TRUE; 
} 

Tworzenie profilu

Utwórz aplikację AppContainer, wywołując metodę CreateAppContainerProfile, z profilem dostępnym dla aplikacji AppContainer za pośrednictwem zmiennej środowiskowej LOCALAPPDATA lub wywołując metodę GetAppContainerFolderPath. W przypadku nowej aplikacji AppContainer zwraca również identyfikator SID pakietu dla aplikacji AppContainer. Jednak w przypadku istniejącej aplikacjiContainer konieczne jest uzyskanie identyfikatora SID pakietu z nazwy moniker przy użyciu interfejsu API DeriveAppContainerSidFromAppContainerName . Zmienne środowiskowe TMP i TEMP są również przekierowywane do katalogu dostępnego dla aplikacji AppContainer w lokalizacji profilu:

LOCALAPPDATA=C:\Users\TestUser\AppData\Local\Packages\TestAppContainer\AC

TEMP=C:\Users\TestUser\AppData\Local\Packages\TestAppContainer\AC\Temp

TMP=C:\Users\TestUser\AppData\Local\Packages\TestAppContainer\AC\Temp

Poniższy przykładowy kod demonstruje użycie funkcji CreateAppContainerProfile w celu utworzenia profilu appContainer i pobrania identyfikatora SID dla nowej lub istniejącej aplikacji AppContainer.

HRESULT
CreateProfileForAppContainer(
    PCWSTR AppContainerName,
    PSID_AND_ATTRIBUTES Capabilities,
    ULONG NumberOfCapabilities,
    PCWSTR DisplayName,
    PCWSTR Description,
    PSID* AppContainerSid
    )
{
    HRESULT hr;
    PSID LocalAppContainerSid = NULL;

    *AppContainerSid = NULL;

    hr = CreateAppContainerProfile(AppContainerName,
                                   DisplayName,
                                   Description,
                                   Capabilities,
                                   NumberOfCapabilities,
                                   &LocalAppContainerSid);

    if (FAILED(hr)) {
        if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)) {

            //
            // Obtain the AppContainer SID based on the AppContainer name.
            //

            hr = AppContainerDeriveSidFromMoniker(AppContainerName,
                                                  &LocalAppContainerSid);
            
            if (FAILED(hr)) {   
                return hr;
            }

        } else {
            return hr;
        }        
    } 

    //
    // Since this is successful, set the output AppContainer SID accordingly.
    //
    
    *AppContainerSid = LocalAppContainerSid;

    return S_OK;
}

Uruchamianie aplikacji AppContainer (lub LPAC)

Aby uruchomić proces AppContainer lub LPAC, należy uwzględnić niektóre pola w strukturze informacji o uruchamianiu STARTUPINFOEX. W szczególności pole lpAttributeList jest wymagane, ponieważ umożliwia to dodatkowe informacje, które instruują createProcess do utworzenia środowiska dla aplikacji AppContainer, który zawiera przestrzeń nazw obiektów i token. Pole lpAttributeList jest typu LPPROC_THREAD_ATTRIBUTE_LIST i jest skonfigurowane w następujący sposób.

W poniższym przykładzie pokazano, jak uruchomić zwykły kontener aplikacji.

STARTUPINFOEX si = {0}; 
LPPROC_THREAD_ATTRIBUTE_LIST AttributeList = NULL; 
SECURITY_CAPABILITIES SecurityCapabilities; 
DWORD AttributeCount = 1; 
SIZE_T AttributesLength = 0; 

if (!InitializeProcThreadAttributeList(NULL, AttributeCount, 0, &AttributesLength)) 
{
    if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)  
    { 
        return GetLastError(); 
    }
} 

AttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 
    0, 
    AttributesLength); 

if (AttributeList == NULL) 
{ 
    return ERROR_OUTOFMEMORY; 
} 

if (!InitializeProcThreadAttributeList(AttributeList, AttributeCount, 0, &AttributesLength)) 
{ 
    if (GetLastError() != ERROR_SUCCESS) 
    {
        return GetLastError(); 
    }
} 

SecurityCapabilities.CapabilityCount = NumberOfCapabilities; 
SecurityCapabilities.Capabilities = Capabilities; 
SecurityCapabilities.AppContainerSid = PackageSid; 
SecurityCapabilities.Reserved = 0; 

if (!UpdateProcThreadAttribute(AttributeList, 
        0,
        PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES, 
        &SecurityCapabilities, 
        sizeof(SecurityCapabilities), 
        NULL, 
        NULL 
        )) 
{ 
    return GetLastError(); 
} 

si.StartupInfo.cb = sizeof(si); 
si.lpAttributeList = AttributeList; 

W poniższym przykładzie pokazano, jak uruchomić mniej uprzywilejowany element AppContainer (LPAC), który wymaga dodatkowego atrybutu procesu/wątku:

STARTUPINFOEX si = {0}; 
LPPROC_THREAD_ATTRIBUTE_LIST AttributeList = NULL; 
SECURITY_CAPABILITIES SecurityCapabilities; 
DWORD AttributeCount = 2; 
SIZE_T AttributesLength = 0; 
DWORD AllApplicationPackagesPolicy; 

if (!InitializeProcThreadAttributeList(NULL, AttributeCount, 0, &AttributesLength)) 
{ 
    if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 
    { 
        return GetLastError(); 
    } 
} 

AttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 
    0, 
    AttributesLength); 

if (AttributeList == NULL) 
{ 
    return ERROR_OUTOFMEMORY; 
} 

if (!InitializeProcThreadAttributeList(AttributeList, AttributeCount, 0, &AttributesLength)) 
{ 
    if (GetLastError() != ERROR_SUCCESS) 
    { 
        return GetLastError(); 
    } 
} 

SecurityCapabilities.CapabilityCount = NumberOfCapabilities; 
SecurityCapabilities.Capabilities = Capabilities; 
SecurityCapabilities.AppContainerSid = PackageSid; 
SecurityCapabilities.Reserved = 0; 

if (!UpdateProcThreadAttribute(AttributeList, 
    0, 
    PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES, 
    &SecurityCapabilities, 
    sizeof(SecurityCapabilities), 
    NULL, 
    NULL 
    )) 
{
    return GetLastError(); 
} 

AllApplicationPackagesPolicy = PROCESS_CREATION_ALL_APPLICATION_PACKAGES_OPT_OUT; 

if (!UpdateProcThreadAttribute(AttributeList, 
    0, 
    PROC_THREAD_ATTRIBUTE_ALL_APPLICATION_PACKAGES_POLICY, 
    &AllApplicationPackagesPolicy, 
    sizeof(AllApplicationPackagesPolicy), 
    NULL, 
    NULL 
    )) 
{ 
    return GetLastError(); 
} 

si.StartupInfo.cb = sizeof(si); 
si.lpAttributeList = AttributeList; 

Tworzenie procesu AppContainer/LPAC

Ostatnim krokiem jest uruchomienie procesu przy użyciu informacji startowych, które obejmują atrybuty procesu/wątku skonstruowane w poprzednich krokach. Obejmuje to identyfikator SID pakietu, możliwości, jeśli istnieją, a także, czy powinien to być LPAC, który jest określony przez rezygnację z wszystkich pakietów aplikacji.

if (!CreateProcess(NULL, 
    <path to executable>, 
    NULL, 
    NULL, 
    FALSE, 
    EXTENDED_STARTUPINFO_PRESENT, 
    NULL, 
    NULL, 
    (LPSTARTUPINFOW)&si, 
    &pi)) 
{ 
    return GetLastError(); 
}

identyfikatory zabezpieczeń

Składniki deskryptora zabezpieczeń