Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Este artigo descreve as etapas necessárias para iniciar um AppContainer ou AppContainer com menos privilégios, incluindo exemplos de código relevantes. AppContainers são um recurso de segurança introduzido no Windows 8 para aprimorar o isolamento e o controle dos processos de aplicativo. Eles fornecem um ambiente em área restrita para aplicativos, restringindo sua capacidade de acessar recursos do sistema ou uns dos outros, bem como dados do usuário, a menos que explicitamente permitidos. Os AppContainers aproveitam os mecanismos de segurança existentes do Windows, como SIDs (identificadores de segurança), tokens e DACL (lista de controle de acesso discricionário) do descritor de segurança, para impor essas restrições.
Terminologia
A tabela a seguir define os termos e conceitos referenciados neste artigo.
| Prazo | Description |
|---|---|
| Identidade do pacote | Uma identidade de pacote é um constructo lógico, identificando exclusivamente um pacote. Para obter mais informações, consulte Uma visão geral da Identidade do Pacote em aplicativos do Windows. |
| Identificador de segurança (SID) | Um SID é usado para identificar exclusivamente uma entidade de segurança ou um grupo de segurança. As entidades de segurança podem representar uma entidade que o sistema operacional seja capaz de autenticar. Os exemplos incluem uma conta de usuário, uma conta de computador, ou um thread ou processo executado no contexto de segurança de uma conta de usuário ou computador. Para obter mais informações, consulte identificadores de segurança |
| SIDs de funcionalidade | Os SIDs de funcionalidade servem como identificadores exclusivos e imutáveis para funcionalidades. Uma funcionalidade representa um token de autoridade que concede a um aplicativo acesso aos recursos (por exemplo, documentos, câmeras e locais). Para obter mais informações, consulte declarações de funcionalidade do aplicativo |
| DACL (Lista de Controle de Acesso Discricionário) | Uma lista que identifica os usuários e grupos que podem executar várias operações em um objeto. Para obter mais informações, consulte os componentes do descritor de segurança. |
| Menos Privileged AppContainers (LPAC) | Um tipo de AppContainer que é mais isolado do que um AppContainer normal. Ele requer declarações de funcionalidade explícitas para acessar recursos acessíveis ao AppContainers. |
Visão geral do AppContainer
Quando um aplicativo é executado como um AppContainer, seu token de acesso inclui uma identidade de pacote de aplicativo exclusiva (SID do pacote) e um ou mais SIDs de funcionalidade. Para AppContainers, os recursos são usados para garantir que o AppContainers possa ser executado com o menor privilégio possível e só tenha acesso a recursos potencialmente confidenciais, se necessário. Por exemplo, sem a funcionalidade de rede , um AppContainer não pode acessar a rede, sem a funcionalidade de webcam que não pode acessar uma câmera. Os SIDs appContainer (SIDs de pacote e funcionalidade) são separados dos SIDs de usuário e grupo tradicionais, com ambas as partes do token sendo necessárias para conceder acesso a um recurso protegido por meio da DACL (lista de controle de acesso discricionário) do objeto. Esse modelo de entidade de segurança dupla garante que o acesso a recursos confidenciais seja fortemente controlado e possa ser gerenciado de forma independente para diferentes aplicativos. Ele também garante que o AppContainers seja explicitamente concedido acesso a um determinado recurso. Além disso, o acesso permitido é a interseção daquela concedida pelos SIDs de usuário/grupo e SIDs appContainer, portanto, se o Usuário tiver acesso completo, mas o AppContainer tiver acesso de leitura apenas, o AppContainer só poderá receber acesso de leitura. Da mesma forma, se o usuário tiver acesso de leitura e execução, mas o AppContainer tiver acesso completo, o AppContainer só poderá receber acesso de leitura e execução.
Os AppContainers são executados com um IL (Nível de Integridade Baixo), que limita ainda mais sua capacidade de interagir com objetos de maior integridade no sistema. No entanto, se um recurso tiver um rótulo obrigatório de IL Médio ou inferior e a DACL conceder acesso por meio do AppContainer (por meio de um SID de Pacote ou SID de Funcionalidade), o AppContainer poderá ler, gravar ou executar dependendo do acesso concedido a ambas as entidades de segurança na DACL. Essa abordagem fornece flexibilidade e segurança, permitindo o acesso aos recursos necessários, restringindo ações potencialmente prejudiciais de aplicativos não confiáveis ou comprometidos.
Os AppContainers são isolados de acessar processos e janelas pertencentes a outros aplicativos, bem como de dispositivos, arquivos/diretórios, chaves do Registro, rede e credenciais. Assim, eles fornecem um mecanismo para proteger possíveis operações arriscadas, como analisar dados não confiáveis com segurança.
Os AppContainers regulares recebem acesso a determinados arquivos/diretórios do sistema, chaves comuns do Registro e objetos COM, no entanto, o LPAC precisa de recursos específicos para acessar recursos que o AppContainers regular pode acessar. Menos AppContainers Privilegiados (LPAC) são ainda mais isolados do que os AppContainers regulares e exigem mais recursos para obter acesso aos recursos aos quais os AppContainers regulares já têm acesso, como o registro, arquivos e outros. Por exemplo, o LPAC não pode abrir chaves no registro, a menos que tenha a funcionalidade RegistryRead e não possa usar COM, a menos que tenha a funcionalidade lpacCom .
Iniciando um AppContainer
Conforme mencionado anteriormente, o AppContainers tem um SID de pacote exclusivo que garante que seus próprios recursos sejam protegidos contra outros aplicativos. O SID do Pacote é derivado de um nome de cadeia de caracteres (moniker) para o AppContainer fornecido. No caso de AppContainers gerados por meio de um manifesto AppX, este é o PFN (Nome da Família de Pacotes), mas no caso de um aplicativo iniciar um processo AppContainer em si, o aplicativo precisa determinar o nome (moniker) que deseja fornecer ao AppContainer.
Há várias etapas envolvidas na inicialização de um AppContainer. Os recursos necessários para conceder precisam ser determinados, o perfil precisa ser criado para o AppContainer para que haja um local em que o AppContainer possa criar/ler/gravar arquivos, atributos de processo e thread precisam ser incluídos para informar ao Windows que ele precisa criar um AppContainer.
Construindo os recursos
Um AppContainer (ou LPAC) pode precisar de recursos para acessar recursos diferentes, como a rede, o local ou no caso de um LPAC até mesmo do registro ou objeto COM. A construção dos recursos pode ser obtida por meio da API DeriveCapabilitySidsFromName , embora seja melhor encapsular essa API em uma função auxiliar, como GetCapabilitySidFromName mostrado no código de exemplo abaixo, já que os SIDs de grupo são usados apenas para serviços e a API retorna apenas uma única funcionalidade.
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;
}
O código de exemplo a seguir demonstra o uso da função auxiliar GetCapabilitySidFromName definida no exemplo anterior para construir os recursos de internetClient e local .
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;
}
Criando o perfil
Crie o AppContainer chamando CreateAppContainerProfile, com o perfil sendo acessível ao AppContainer por meio da variável de ambiente LOCALAPPDATA ou chamando GetAppContainerFolderPath. Para um novo AppContainer, isso também retorna o SID do Pacote para o AppContainer. No entanto, para um AppContainer existente, é necessário derivar o SID do pacote do moniker usando a API DeriveAppContainerSidFromAppContainerName . As variáveis de ambiente TMP e TEMP também são redirecionadas para um diretório acessível ao AppContainer no local do 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
O código de exemplo a seguir demonstra o uso da função CreateAppContainerProfile para criar um perfil AppContainer e recuperar o SID para um AppContainer novo ou 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;
}
Iniciando o AppContainer (ou LPAC)
Para iniciar o processo AppContainer ou LPAC, é necessário incluir determinados campos na estrutura de informações de inicialização, STARTUPINFOEX. Especificamente, o campo lpAttributeList é necessário, pois isso permite informações adicionais que instruam CreateProcess a criar o ambiente para o AppContainer, que inclui o namespace e o token do objeto. O campo lpAttributeList é do tipo LPPROC_THREAD_ATTRIBUTE_LIST e é configurado da seguinte maneira.
O exemplo a seguir mostra como iniciar um contêiner de aplicativo regular.
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;
O exemplo a seguir mostra como iniciar um AppContainer (LPAC) menos privilegiado, o que requer um atributo de processo/thread 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;
Criando o processo AppContainer/LPAC
A etapa final é iniciar o processo usando as informações de inicialização, que incluem os atributos de processo/thread construídos nas etapas anteriores. Isso incluirá o SID do pacote, os recursos, se houver, bem como se este deve ser um LPAC, que é especificado ao recusar Todos os Pacotes de Aplicativos.
if (!CreateProcess(NULL,
<path to executable>,
NULL,
NULL,
FALSE,
EXTENDED_STARTUPINFO_PRESENT,
NULL,
NULL,
(LPSTARTUPINFOW)&si,
&pi))
{
return GetLastError();
}