Compartir a través de


Inicio de appContainer

En este artículo se describen los pasos necesarios para iniciar appContainer o AppContainer con menos privilegios, incluidos los ejemplos de código pertinentes. AppContainers son una característica de seguridad introducida en Windows 8 para mejorar el aislamiento y el control de los procesos de aplicación. Proporcionan un entorno de espacio aislado para las aplicaciones, lo que restringe su capacidad de acceder al sistema o a los recursos de los demás, así como a los datos de usuario, a menos que se permita explícitamente. AppContainers aprovecha los mecanismos de seguridad existentes de Windows, como identificadores de seguridad (SID), tokens y lista de control de acceso discrecional (DACL) del descriptor de seguridad para aplicar estas restricciones.

Terminología

En la tabla siguiente se definen los términos y conceptos a los que se hace referencia en este artículo.

Término Description
Identidad del paquete Una identidad de paquete es una construcción lógica que identifica de forma única un paquete. Para obtener más información, consulte Introducción a la identidad del paquete en aplicaciones de Windows.
Identificador de seguridad (SID) Un SID se usa para identificar de forma única una entidad de seguridad o un grupo de seguridad. Las entidades de seguridad pueden representar cualquier entidad que el sistema operativo pueda autenticar. Algunos ejemplos son una cuenta de usuario, una cuenta de equipo o un subproceso o proceso que se ejecuta en el contexto de seguridad de una cuenta de usuario o equipo. Para más información, consulte Identificadores de seguridad.
SID de funcionalidad Los SID de funcionalidad sirven como identificadores únicos e inmutables para las funcionalidades. Una funcionalidad representa un token de autoridad irreforable que concede a una aplicación acceso a los recursos (por ejemplo, documentos, cámaras y ubicaciones). Para obtener más información, consulte Declaraciones de funcionalidad de la aplicación.
Lista de control de acceso discrecional (DACL) Lista que identifica los usuarios y grupos que pueden realizar diversas operaciones en un objeto. Para obtener más información, consulte Componentes del descriptor de seguridad.
AppContainers con menos privilegios (LPAC) Tipo de AppContainer que está más aislado que un AppContainer normal. Requiere declaraciones de funcionalidad explícitas para acceder a los recursos a los que se puede acceder a AppContainers.

Introducción a AppContainer

Cuando una aplicación se ejecuta como appContainer, su token de acceso incluye una identidad de paquete de aplicación única (SID de paquete) y uno o varios SID de funcionalidad. Para AppContainers, las funcionalidades se usan para asegurarse de que AppContainers se puede ejecutar con el privilegio mínimo posible y solo se les concede acceso a recursos potencialmente confidenciales si es necesario. Por ejemplo, sin la funcionalidad de red , un AppContainer no puede acceder a la red, sin la funcionalidad de cámara web que no puede acceder a una cámara. Los SID de AppContainer (SID de paquete y funcionalidad) son independientes de los SID de usuario y grupo tradicionales con ambas partes del token que se requieren para conceder acceso a un recurso protegido a través de la lista de control de acceso discrecional (DACL) del objeto. Este modelo de doble entidad de seguridad garantiza que el acceso a los recursos confidenciales está estrechamente controlado y se puede administrar independientemente para diferentes aplicaciones. También garantiza que AppContainers tenga acceso explícitamente a un recurso determinado. Además, el acceso permitido es la intersección de la que conceden los SID de usuario o grupo y los SID de AppContainer, por lo que si el usuario tiene acceso completo, pero appContainer solo tiene acceso de lectura, solo se puede conceder acceso de lectura a AppContainer. Del mismo modo, si el usuario tiene acceso de lectura y ejecución, pero appContainer tiene acceso completo a AppContainer solo se puede conceder acceso de lectura y ejecución.

AppContainers se ejecuta con un nivel de integridad bajo (IL), que limita aún más su capacidad de interactuar con objetos de mayor integridad en el sistema. Sin embargo, si un recurso tiene una etiqueta obligatoria de IL medio o inferior y la DACL concede acceso a appContainer (a través de un SID de paquete o SID de funcionalidad), AppContainer puede leer, escribir o ejecutar en función del acceso concedido a ambas entidades de seguridad en la DACL. Este enfoque proporciona flexibilidad y seguridad, lo que permite el acceso a los recursos necesarios, al tiempo que restringe las acciones potencialmente perjudiciales de aplicaciones que no son de confianza o en peligro.

Los appContainers están aislados de acceder a procesos y ventanas que pertenecen a otras aplicaciones, así como de dispositivos, archivos o directorios, claves del Registro, la red y las credenciales. Por lo tanto, proporcionan un mecanismo para las operaciones de riesgo potenciales de espacio aislado, como analizar datos que no son de confianza de forma segura.

Los appContainers normales tienen acceso a determinados archivos o directorios del sistema, claves comunes del Registro y objetos COM; sin embargo, LPAC necesita funcionalidades específicas para acceder a los recursos a los que los appContainers normales pueden acceder. Los appContainers con menos privilegios (LPAC) son aún más aislados que los appContainers normales y requieren más funcionalidades para obtener acceso a los recursos a los que appContainers normales ya tienen acceso, como el registro, los archivos y otros. Por ejemplo, LPAC no puede abrir ninguna clave en el Registro a menos que tenga la funcionalidad registryRead y no pueda usar COM a menos que tenga la funcionalidad lpacCom .

Inicio de appContainer

Como se mencionó anteriormente, AppContainers tiene un SID de paquete único que garantiza que sus propios recursos estén protegidos de otras aplicaciones. El SID de paquete se deriva de un nombre de cadena (moniker) para el appContainer especificado. En el caso de AppContainers generado a través de un manifiesto de AppX, este es el nombre de familia del paquete (PFN), pero en el caso de una aplicación que inicia un proceso de AppContainer, la aplicación debe determinar el nombre (moniker) que desea dar al AppContainer.

Hay varios pasos implicados en el inicio de appContainer. Es necesario determinar las funcionalidades necesarias para conceder, el perfil debe crearse para AppContainer para que haya una ubicación donde AppContainer pueda crear, leer y escribir archivos, procesar y atributos de subproceso para informar a Windows de que necesita crear un AppContainer.

Construcción de las funcionalidades

Un AppContainer (o LPAC) puede necesitar funcionalidades para acceder a distintos recursos, como la red, la ubicación o, en el caso de un LPAC, incluso el registro o el objeto COM. La construcción de las funcionalidades se puede lograr mediante la API DeriveCapabilitySidsFromName , aunque es mejor ajustar esta API en una función auxiliar, como GetCapabilitySidFromName que se muestra en el código de ejemplo siguiente, ya que los SID de grupo solo se usan para los servicios y la API solo devuelve una sola funcionalidad.

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

En el código de ejemplo siguiente se muestra el uso de la función auxiliar GetCapabilitySidFromName definida en el ejemplo anterior para construir las funcionalidades internetClient y 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; 
} 

Crear el perfil

Cree appContainer llamando a CreateAppContainerProfile, con el perfil al que se puede acceder a AppContainer a través de la variable de entorno LOCALAPPDATA o llamando a GetAppContainerFolderPath. Para un nuevo AppContainer, también devuelve el SID de paquete para AppContainer. Sin embargo, para un AppContainer existente es necesario derivar el SID del paquete del moniker mediante la API DeriveAppContainerSidFromAppContainerName . Las variables de entorno TMP y TEMP también se redirigen a un directorio accesible para AppContainer en la ubicación del perfil:

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

En el código de ejemplo siguiente se muestra el uso de la función CreateAppContainerProfile para crear un perfil de AppContainer y recuperar el SID de un appContainer nuevo o existente.

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

Inicio de AppContainer (o LPAC)

Para iniciar el proceso de AppContainer o LPAC, es necesario incluir determinados campos en la estructura de información de inicio , STARTUPINFOEX. En concreto, se requiere el campo lpAttributeList , ya que permite información adicional que indica a CreateProcess que cree el entorno para appContainer, que incluye el espacio de nombres de objeto y el token. El campo lpAttributeList es de tipo LPPROC_THREAD_ATTRIBUTE_LIST y se configura de la manera siguiente.

En el ejemplo siguiente se muestra cómo iniciar un contenedor de aplicaciones normal.

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; 

En el ejemplo siguiente se muestra cómo iniciar un AppContainer (LPAC) con menos privilegios, que requiere un atributo de proceso o subproceso adicional:

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; 

Creación del proceso AppContainer/LPAC

El último paso es iniciar el proceso mediante la información de inicio, que incluye los atributos process/thread construidos en los pasos anteriores. Esto incluirá el SID del paquete, las funcionalidades, si las hay, así como si esto debería ser un LPAC, que se especifica al no participar en todos los paquetes de aplicación.

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

Identificadores de seguridad

Componentes del descriptor de seguridad