Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Este artigo descreve as etapas necessárias para iniciar um AppContainer ou Less-Privileged AppContainer, incluindo exemplos de código relevantes. AppContainers são um recurso de segurança introduzido no Windows 8 para melhorar o isolamento e o controle de processos de aplicativos. Eles fornecem um ambiente de área restrita para aplicativos, restringindo sua capacidade de acessar o sistema ou os recursos uns dos outros, bem como os dados do usuário, a menos que explicitamente permitido. O AppContainers aproveita os mecanismos de segurança existentes do Windows, como identificadores de segurança (SIDs), tokens e lista de controle de acesso discricionário (DACL) do descritor de segurança, para impor essas restrições.
Terminologia
A tabela a seguir define termos e conceitos referenciados neste artigo.
| Term | Description |
|---|---|
| Identidade do pacote | Uma identidade de pacote é uma construção lógica, identificando exclusivamente um pacote. Para obter mais informações, consulte Visão geral da identidade do pacote em aplicativos do Windows. |
| Identificador de segurança (SID) | Um SID é utilizado para identificar de forma única uma entidade de segurança ou um grupo de segurança. As entidades de segurança podem representar qualquer entidade que o sistema operativo possa 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 um usuário ou conta de computador. Para obter mais informações, consulte Identificadores de segurança |
| Identificadores de Capacidade (SIDs) | Os SIDs de capacidade servem como identificadores exclusivos e imutáveis para os recursos. Um recurso representa um token de autoridade não falsificável que concede a um aplicativo acesso a recursos (por exemplo, documentos, câmeras e locais). Para obter mais informações, consulte Declarações de capacidade do aplicativo |
| Lista de Controle de Acesso Discricionário (DACL) | 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 Componentes do descritor de segurança. |
| AppContainers menos privilegiados (LPAC) | Um tipo de AppContainer que é mais isolado do que um AppContainer normal. Ele requer declarações de capacidade explícitas para acessar recursos que são acessíveis a 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 de pacote) e um ou mais SIDs de capacidade. Para AppContainers, os recursos são usados para garantir que 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 capacidade de rede , um AppContainer não pode acessar a rede, sem o recurso de webcam ele não pode acessar uma câmera. Os SIDs AppContainer (SIDs de pacote e capacidade) 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 lista de controle de acesso discricionário (DACL) do objeto. Esse modelo de dupla entidade garante que o acesso a recursos confidenciais seja rigorosamente controlado e possa ser gerenciado de forma independente para diferentes aplicativos. Ele também garante que AppContainers tenha acesso explícito a um determinado recurso. Além disso, o acesso permitido é a interseção do concedido pelos SIDs de usuário/grupo e SIDs AppContainer, portanto, se o Usuário tiver acesso total, mas o AppContainer só tiver acesso de leitura, o AppContainer só poderá receber acesso de leitura. Da mesma forma, se o usuário tiver acesso read & execute, mas o AppContainer tiver acesso total, o AppContainer só poderá receber acesso read & execute.
Os AppContainers são executados com um IL (Low Integrity Level), o 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 capacidade), o AppContainer poderá ler, gravar ou executar, dependendo do acesso concedido a ambos os principais na DACL. Essa abordagem oferece flexibilidade e segurança, permitindo o acesso aos recursos necessários e, ao mesmo tempo, restringindo ações potencialmente prejudiciais de aplicativos não confiáveis ou comprometidos.
Os AppContainers são isolados do acesso a 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 sandboxing de operações potencialmente arriscadas, como a análise segura de dados não confiáveis.
AppContainers regulares recebem acesso a determinados arquivos/diretórios do sistema, chaves de registro comuns e objetos COM, no entanto, o LPAC precisa de recursos específicos para acessar recursos que AppContainers regulares podem acessar. Os AppContainers menos privilegiados (LPAC) são ainda mais isolados do que os AppContainers normais e exigem mais recursos para obter acesso a recursos aos quais os AppContainers regulares já têm acesso, como o registro, arquivos e outros. Por exemplo, a LPAC não pode abrir nenhuma chave no Registro, a menos que tenha o recurso registryRead e não possa usar COM, a menos que tenha a capacidade lpacCom .
Iniciando um AppContainer
Como mencionado anteriormente, os AppContainers têm um SID de pacote exclusivo que garante que seus próprios recursos sejam protegidos de 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 Package Family Name (PFN), mas no caso de um aplicativo iniciar um processo AppContainer em si, o aplicativo precisa determinar o nome (moniker) que deseja dar 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 onde 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 as capacidades
Um AppContainer (ou LPAC) pode precisar de recursos para acessar diferentes recursos, como a rede, o local ou, no caso de um LPAC, até mesmo o registro ou objeto COM. A construção dos recursos pode ser alcançada por meio da API DeriveCapabilitySidsFromName , embora seja melhor encapsular essa API em uma função auxiliar, como GetCapabilitySidFromName mostrada no código de exemplo abaixo, já que os SIDs de grupo são usados apenas para serviços e a API retorna apenas um único recurso.
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 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;
}
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 da inicialização, STARTUPINFOEX. Especificamente, o campo lpAttributeList é necessário, pois isso permite informações adicionais que instruem CreateProcess a criar o ambiente para o AppContainer, que inclui o objeto, namespace e token. O campo lpAttributeList é do tipo LPPROC_THREAD_ATTRIBUTE_LIST e é configurado da seguinte forma.
O exemplo a seguir mostra como iniciar um contêiner de aplicativo 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;
O exemplo a seguir mostra como iniciar um AppContainer (LPAC) menos privilegiado, 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, recursos, se houver, bem como se este deve ser um LPAC, que é especificado pela exclusão de Todos os Pacotes de Aplicativos.
if (!CreateProcess(NULL,
<path to executable>,
NULL,
NULL,
FALSE,
EXTENDED_STARTUPINFO_PRESENT,
NULL,
NULL,
(LPSTARTUPINFOW)&si,
&pi))
{
return GetLastError();
}