Запуск AppContainer

В этой статье описаны шаги, необходимые для запуска AppContainer или Менее привилегированного appContainer, включая соответствующие примеры кода. AppContainers — это функция безопасности, представленная в Windows 8 для повышения изоляции и управления процессами приложений. Они предоставляют песочницу среду для приложений, ограничивая возможность доступа к системе или ресурсам друг друга, а также пользовательские данные, если не разрешено явным образом. AppContainers использует существующие механизмы безопасности Windows, такие как идентификаторы безопасности (SID), маркеры и список дескрипторных дескрипторов безопасности (DACL), для применения этих ограничений.

Терминология

В следующей таблице определены термины и понятия, на которые ссылается эта статья.

Срок Description
Удостоверение пакета Удостоверение пакета — это логическая конструкция, однозначно определяющая пакет. Дополнительные сведения см . в разделе "Общие сведения о удостоверении пакета" в приложениях Windows.
Идентификатор безопасности (SID) SID используется для уникальной идентификации участника безопасности или группы безопасности. Участники безопасности могут представлять любой объект, подлинность которого может быть выполнена операционной системой. Примерами могут служить учетная запись пользователя, учетная запись компьютера, поток или процесс, выполняемый в контексте безопасности пользователя или учетной записи компьютера. Дополнительные сведения см. в разделе " Идентификаторы безопасности"
Идентификаторы возможностей (SID) SID возможностей служат уникальными и неизменяемыми идентификаторами возможностей. Возможность представляет неуправляемый маркер центра, который предоставляет приложению доступ к ресурсам (например, документам, камерам и расположениям). Дополнительные сведения см. в объявлениях возможностей приложений
Список управления доступом по усмотрению (DACL) Список, определяющий пользователей и группы, которые могут выполнять различные операции с объектом. Дополнительные сведения см. в разделе "Компоненты дескриптора безопасности".
Less Privileged AppContainers (LPAC) Тип AppContainer, который более изолирован, чем обычный AppContainer. Для доступа к ресурсам, доступным для AppContainers, требуются явные объявления возможностей.

Обзор AppContainer

Когда приложение выполняется в качестве AppContainer, его маркер доступа включает уникальное удостоверение пакета приложения (SID пакета) и один или несколько идентификаторов безопасности. Для AppContainers возможности используются, чтобы гарантировать, что AppContainers может работать с минимальными привилегиями и предоставлять доступ только к потенциально конфиденциальным ресурсам при необходимости. Например, без сетевой возможности AppContainer не может получить доступ к сети, без возможности веб-камеры он не может получить доступ к камере. Идентификаторы SID AppContainer (пакеты и идентификаторы SID возможностей) отделены от традиционных идентификаторов безопасности пользователей и групп с обеими частями маркера, необходимыми для предоставления доступа к защищенному ресурсу через список управления доступом объекта (DACL). Эта модель с двумя субъектами гарантирует, что доступ к конфиденциальным ресурсам жестко контролируется и может управляться независимо для разных приложений. Он также гарантирует, что AppContainers должен быть явно предоставлен доступ к заданному ресурсу. Кроме того, разрешенный доступ — это пересечение, которое предоставляется идентификаторами SID пользователя или группы и идентификаторами SID AppContainer, поэтому, если у пользователя есть полный доступ, но AppContainer имеет доступ только для чтения, AppContainer может быть предоставлен только для чтения. Аналогичным образом, если пользователь имеет доступ на чтение и выполнение, но AppContainer имеет полный доступ к AppContainer, можно предоставить доступ только для чтения и выполнения.

AppContainers выполняется с низким уровнем целостности (IL), что дополнительно ограничивает возможность взаимодействия с объектами более высокой целостности в системе. Однако если ресурс имеет обязательную метку среднего il или ниже, а DACL предоставляет доступ к AppContainer (через идентификатор безопасности пакета или идентификатор безопасности возможностей), appContainer может читать, записывать или выполнять в зависимости от доступа, предоставленного обоим субъектам в DACL. Этот подход обеспечивает гибкость и безопасность, позволяя получить доступ к необходимым ресурсам при ограничении потенциально опасных действий из ненадежных или скомпрометированных приложений.

AppContainers изолированы от доступа к процессам и окнам, принадлежащим другим приложениям, а также от устройств, файлов и каталогов, разделов реестра, сети и учетных данных. Таким образом, они предоставляют механизм для песочницы потенциальных рискованных операций, таких как анализ ненадежных данных безопасно.

Обычные приложенияContainers получают доступ к определенным системным файлам и каталогам, общим разделам реестра и com-объектам, однако LPAC требует определенных возможностей для доступа к ресурсам, к которым обычные AppContainers могут получить доступ. Менее привилегированные приложенияContainers (LPAC) еще более изолированы, чем обычные AppContainers и требуют дополнительных возможностей для получения доступа к ресурсам, к которым обычные ПриложенияContainers уже имеют доступ к таким ресурсам, как реестр, файлы и другие. Например, LPAC не может открывать ключи в реестре, если он не имеет возможности реестраRead и не может использовать COM, если он не имеет возможности lpacCom .

Запуск AppContainer

Как упоминалось ранее, AppContainers имеет уникальный идентификатор безопасности пакета, обеспечивающий защиту собственных ресурсов от других приложений. Идентификатор безопасности пакета является производным от имени строки (moniker) для заданного AppContainer. В случае AppContainers, разреженного через манифест AppX, это имя семейства пакетов (PFN), но в случае запуска самого процесса AppContainer приложение должно определить имя (moniker), которое он хочет дать AppContainer.

Существует несколько шагов, связанных с запуском AppContainer. Необходимые возможности, необходимые для определения, необходимо создать профиль для AppContainer, чтобы в нем существовало расположение, в котором AppContainer может создавать и записывать файлы, процессы и потоковые атрибуты, чтобы сообщить Windows, что он должен создать AppContainer.

Создание возможностей

Приложению AppContainer (или LPAC) может потребоваться возможность доступа к различным ресурсам, таким как сеть, расположение или в случае с LPAC даже реестром или com-объектом. Создание возможностей можно достичь с помощью API DeriveCapabilitySidsFromName , хотя лучше упаковать этот API в вспомогательной функции, например GetCapabilitySidFromName , показанную в приведенном ниже примере кода, так как идентификаторы групп используются только для служб и API только когда-либо возвращает одну возможность.

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

В следующем примере кода показано использование вспомогательной функции GetCapabilitySidFromName , определенной в предыдущем примере для создания возможностей internetClient и расположения .

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

Создание профиля

Создайте AppContainer, вызвав CreateAppContainerProfile, с профилем, доступным для AppContainer через переменную среды LOCALAPPDATA или вызвав GetAppContainerFolderPath. Для нового AppContainer этот идентификатор также возвращает идентификатор безопасности пакета для AppContainer. Однако для существующего AppContainer необходимо наследить идентификатор безопасности пакета от моникера с помощью API DeriveAppContainerSidFromAppContainerName . Переменные среды TMP и TEMP также перенаправляются в каталог, доступный для AppContainer в расположении профиля:

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

В следующем примере кода показано использование функции CreateAppContainerProfile для создания профиля AppContainer и получения идентификатора безопасности для нового или существующего 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;
}

Запуск AppContainer (или LPAC)

Чтобы запустить процесс AppContainer или LPAC, необходимо включить определенные поля в структуру сведений о запуске, STARTUPINFOEX. В частности, требуется поле lpAttributeList , так как это позволяет получить дополнительную информацию, которая предписывает CreateProcess создать среду для AppContainer, включающую пространство имен объекта и маркер. Поле lpAttributeList имеет тип LPPROC_THREAD_ATTRIBUTE_LIST и настраивается следующим образом.

В следующем примере показано, как запустить обычный контейнер приложений.

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; 

В следующем примере показано, как запустить менее привилегированный AppContainer (LPAC), для которого требуется дополнительный атрибут процесса или потока:

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; 

Создание процесса AppContainer/LPAC

Последним шагом является запуск процесса с помощью информации о запуске, которая включает атрибуты процесса или потока, созданные на предыдущих шагах. К ним относятся идентификатор безопасности пакета, возможности, если таковые имеются, а также если это должен быть LPAC, который указан путем отказа от всех пакетов приложений.

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

Идентификаторы безопасности

Компоненты дескриптора безопасности