Condividi tramite


Avviare un AppContainer

Questo articolo descrive i passaggi necessari per avviare un AppContainer o Un appContainer con privilegi minori, inclusi esempi di codice pertinenti. AppContainers è una funzionalità di sicurezza introdotta in Windows 8 per migliorare l'isolamento e il controllo dei processi dell'applicazione. Forniscono un ambiente in modalità sandbox per le applicazioni, limitando la possibilità di accedere al sistema o alle risorse dell'altro, nonché ai dati utente, a meno che non siano consentiti in modo esplicito. AppContainers sfrutta i meccanismi di sicurezza di Windows esistenti, ad esempio gli identificatori di sicurezza (SID), i token e l'elenco di controllo di accesso discrezionale (DACL) del descrittore di sicurezza per applicare queste restrizioni.

Terminologia

La tabella seguente definisce termini e concetti a cui si fa riferimento in questo articolo.

Termine Description
Identità del pacchetto Un'identità del pacchetto è un costrutto logico che identifica in modo univoco un pacchetto. Per altre informazioni, vedere Panoramica dell'identità del pacchetto nelle app di Windows.
Identificatore di sicurezza (SID) Un SID viene usato per identificare in modo univoco un'entità di sicurezza o un gruppo di sicurezza. Le entità di sicurezza possono rappresentare qualsiasi entità che il sistema operativo possa autenticare. Gli esempi includono un account utente, un account computer o un thread o un processo che viene eseguito nel contesto di sicurezza di un account utente o computer. Per altre informazioni, vedere Identificatori di sicurezza
SID di capacità I SID di funzionalità fungono da identificatori univoci e non modificabili per le funzionalità. Una funzionalità rappresenta un token di autorità non verificabile che concede a un'applicazione l'accesso alle risorse , ad esempio documenti, fotocamere e posizioni. Per altre informazioni, vedere Dichiarazioni di funzionalità delle app
Elenco di controllo di accesso discrezionale (DACL) Elenco che identifica gli utenti e i gruppi che possono eseguire varie operazioni su un oggetto. Per altre informazioni, vedere Componenti del descrittore di sicurezza.
Less Privileged AppContainers (LPAC) Tipo di AppContainer più isolato rispetto a un normale AppContainer. Richiede dichiarazioni di funzionalità esplicite per accedere alle risorse accessibili ad AppContainers.

Panoramica di AppContainer

Quando un'applicazione viene eseguita come AppContainer, il token di accesso include un'identità univoca del pacchetto dell'applicazione (SID pacchetto) e uno o più SID di funzionalità. Per AppContainers, le funzionalità vengono usate per garantire che AppContainers possa essere eseguito con il privilegio minimo possibile e concedere l'accesso solo alle risorse potenzialmente sensibili, se necessario. Ad esempio, senza la funzionalità di rete , un AppContainer non può accedere alla rete, senza la funzionalità webcam non può accedere a una fotocamera. I SID appContainer (SID pacchetto e funzionalità) sono separati dai SID di gruppo e utente tradizionali con entrambe le parti del token necessarie per concedere l'accesso a una risorsa protetta tramite l'elenco di controllo di accesso discrezionale (DACL) dell'oggetto. Questo modello a due entità garantisce che l'accesso alle risorse sensibili sia strettamente controllato e possa essere gestito in modo indipendente per applicazioni diverse. Garantisce inoltre che AppContainers debba concedere in modo esplicito l'accesso a una determinata risorsa. Inoltre, l'accesso consentito è l'intersezione di quello concesso dai SID utente/gruppo e dai SID appContainer, quindi se l'utente ha accesso completo, ma AppContainer ha solo accesso in lettura, AppContainer può essere concesso solo l'accesso in lettura. Analogamente, se l'utente ha accesso in lettura ed esecuzione, ma AppContainer ha accesso completo all'AppContainer può essere concesso solo l'accesso in lettura ed esecuzione.

AppContainers viene eseguito con un livello di integrità basso (IL), che limita ulteriormente la capacità di interagire con oggetti di integrità superiore nel sistema. Tuttavia, se una risorsa ha un'etichetta obbligatoria di MEDIA IL o inferiore e l'elenco DACL concede l'accesso tramite AppContainer (tramite un SID del pacchetto o un SID della funzionalità), AppContainer può leggere, scrivere o eseguire a seconda dell'accesso concesso a entrambe le entità nell'elenco di controllo di accesso. Questo approccio offre flessibilità e sicurezza, consentendo l'accesso alle risorse necessarie, limitando al contempo azioni potenzialmente dannose da applicazioni non attendibili o compromesse.

AppContainers è isolato dall'accesso a processi e finestre appartenenti ad altre applicazioni, nonché da dispositivi, file/directory, chiavi del Registro di sistema, rete e credenziali. Di conseguenza, forniscono un meccanismo per la sandboxing di potenziali operazioni rischiose, ad esempio l'analisi dei dati non attendibili in modo sicuro.

Ai normali AppContainers viene concesso l'accesso a determinati file/directory di sistema, chiavi comuni del Registro di sistema e oggetti COM, ma LPAC richiede funzionalità specifiche per accedere alle risorse a cui possono accedere i normali AppContainers. AppContainers con privilegi inferiori (LPAC) sono ancora più isolati rispetto ai normali AppContainers e richiedono ulteriori funzionalità per ottenere l'accesso alle risorse a cui i normali AppContainers hanno già accesso, ad esempio il Registro di sistema, i file e altri. Ad esempio, LPAC non può aprire chiavi nel Registro di sistema a meno che non disponga della funzionalità RegistryRead e non possa usare COM a meno che non disponga della funzionalità lpacCom .

Avvio di un AppContainer

Come accennato in precedenza, AppContainers ha un SID pacchetto univoco che garantisce che le proprie risorse siano protette da altre applicazioni. Il SID del pacchetto è derivato da un nome stringa (moniker) per l'appContainer specificato. Nel caso di AppContainers generato tramite un manifesto AppX, si tratta del nome della famiglia di pacchetti (PFN), ma nel caso di un'applicazione che avvia un processo AppContainer stesso, l'applicazione deve determinare il nome (moniker) che vuole assegnare a AppContainer.

L'avvio di un AppContainer comporta diversi passaggi. Le funzionalità necessarie per concedere devono essere determinate, il profilo deve essere creato per AppContainer in modo che sia presente un percorso in cui AppContainer può creare/leggere/scrivere file, elaborare e thread attributi deve essere incluso per informare Windows che deve creare un AppContainer.

Creazione delle funzionalità

Un AppContainer (o LPAC) potrebbe richiedere funzionalità per accedere a risorse diverse, ad esempio la rete, il percorso o nel caso di un LPAC anche il Registro di sistema o l'oggetto COM. La creazione delle funzionalità può essere ottenuta tramite l'API DeriveCapabilitySidsFromName , anche se è preferibile eseguire il wrapping di questa API in una funzione helper, ad esempio GetCapabilitySidFromName illustrata nel codice di esempio seguente, poiché i SID di gruppo vengono usati solo per i servizi e l'API restituisce solo una singola funzionalità.

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

Il codice di esempio seguente illustra l'uso della funzione helper GetCapabilitySidFromName definita nell'esempio precedente per costruire le funzionalità internetClient e location .

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

Creazione del profilo

Creare AppContainer chiamando CreateAppContainerProfile, con il profilo accessibile all'AppContainer tramite la variabile di ambiente LOCALAPPDATA o chiamando GetAppContainerFolderPath. Per un nuovo AppContainer, viene restituito anche il SID del pacchetto per AppContainer. Tuttavia, per un AppContainer esistente è necessario derivare il SID del pacchetto dal moniker usando l'API DeriveAppContainerSidFromAppContainerName . Entrambe le variabili di ambiente TMP e TEMP vengono reindirizzate a una directory accessibile a AppContainer nel percorso del profilo:

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

Il codice di esempio seguente illustra l'uso della funzione CreateAppContainerProfile per creare un profilo AppContainer e recuperare il SID per un oggetto AppContainer nuovo o esistente.

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

Avvio di AppContainer (o LPAC)

Per avviare il processo AppContainer o LPAC, è necessario includere determinati campi nella struttura delle informazioni di avvio STARTUPINFOEX. In particolare, il campo lpAttributeList è obbligatorio perché consente informazioni aggiuntive che indicano a CreateProcess di creare l'ambiente per AppContainer che include lo spazio dei nomi e il token dell'oggetto. Il campo lpAttributeList è di tipo LPPROC_THREAD_ATTRIBUTE_LIST ed è configurato come segue.

L'esempio seguente illustra come avviare un contenitore di app normale.

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; 

L'esempio seguente illustra come avviare un'appContainer con privilegi inferiori (LPAC), che richiede un attributo di processo/thread aggiuntivo:

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; 

Creazione del processo AppContainer/LPAC

Il passaggio finale consiste nell'avviare il processo usando le informazioni di avvio, che includono gli attributi di processo/thread costruiti nei passaggi precedenti. Questo includerà il SID del pacchetto, le funzionalità, se presenti, nonché se deve essere un LPAC, specificato esplicitamente da Tutti i pacchetti dell'applicazione.

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

Identificatori di sicurezza

Componenti del descrittore di sicurezza