次の方法で共有


AppContainer を起動する

この記事では、関連するコード例を含め、AppContainer または Less-Privileged AppContainer を起動するために必要な手順について説明します。 AppContainers は、アプリケーション プロセスの分離と制御を強化するために Windows 8 で導入されたセキュリティ機能です。 アプリケーションにサンドボックス環境を提供し、明示的に許可されない限り、システムまたは相互のリソースにアクセスする機能とユーザー データを制限します。 AppContainers は、セキュリティ識別子 (SID)、トークン、セキュリティ記述子随意アクセス制御リスト (DACL) などの既存の Windows セキュリティ メカニズムを利用して、これらの制限を適用します。

用語

次の表では、この記事で参照される用語と概念を定義します。

任期 Description
パッケージ ID パッケージ ID は、パッケージを一意に識別する論理コンストラクトです。 詳細については、「 Windows アプリのパッケージ ID の概要」を参照してください。
セキュリティ識別子 (SID) SID は、セキュリティ プリンシパルまたはセキュリティ グループを一意に識別するために使用されます。 セキュリティ プリンシパルは、オペレーティング システムが認証できる任意のエンティティを表すことができます。 たとえば、ユーザー アカウント、コンピューター アカウント、またはユーザーまたはコンピューター アカウントのセキュリティ コンテキストで実行されるスレッドまたはプロセスがあります。 詳細については、「セキュリティ識別子」を参照してください。
機能 SID 機能 SID は、機能の一意の不変識別子として機能します。 機能は、アプリケーションにリソース (ドキュメント、カメラ、場所など) へのアクセスを許可する、偽造不可能な権限トークンを表します。 詳細については、「アプリ機能の宣言」を参照してください。
随意アクセス制御リスト (DACL) オブジェクトに対してさまざまな操作を実行できるユーザーとグループを識別するリスト。 詳細については、「 セキュリティ記述子コンポーネント」を参照してください。
Less Privileged AppContainers (LPAC) 通常の AppContainer よりも分離された AppContainer の種類。 AppContainers からアクセスできるリソースにアクセスするには、明示的な機能宣言が必要です。

AppContainer の概要

アプリケーションが AppContainer として実行される場合、そのアクセス トークンには、一意のアプリケーション パッケージ ID (パッケージ SID) と 1 つ以上の機能 SID が含まれます。 AppContainers の場合、機能は、AppContainers が可能な限り最小限の特権で実行でき、必要に応じて機密性の高いリソースへのアクセス権のみを付与するために使用されます。 たとえば、 ネットワーク 機能がないと、AppContainer はカメラにアクセスできない Web カメラ 機能がないと、ネットワークにアクセスできません。 AppContainer SID (パッケージおよび機能 SID) は、オブジェクトの随意アクセス制御リスト (DACL) を介して保護されたリソースへのアクセスを許可するためにトークンの両方の部分が必要な従来のユーザーおよびグループ SID とは別です。 このデュアル プリンシパル モデルにより、機密性の高いリソースへのアクセスが厳密に制御され、さまざまなアプリケーションに対して個別に管理できます。 また、AppContainers に特定のリソースへのアクセス権を明示的に付与する必要もあります。 さらに、許可されるアクセスは、ユーザー/グループ SID と AppContainer SID によって付与された共通部分であるため、ユーザーがフル アクセスを持っていても、AppContainer に読み取りアクセス権しかない場合、AppContainer には読み取りアクセス権のみを付与できます。 同様に、ユーザーが読み取りおよび実行アクセス権を持っていて、AppContainer にフル アクセス権がある場合、AppContainer には読み取りアクセスと実行アクセスのみを許可できます。

AppContainers は低整合性レベル (IL) で実行され、システム上の整合性の高いオブジェクトと対話する機能がさらに制限されます。 ただし、リソースに Medium IL 以下の必須ラベルがあり、DACL が AppContainer へのアクセスを (パッケージ SID または機能 SID を介して) 許可する場合、AppContainer は DACL の両方のプリンシパルに付与されたアクセスに応じて読み取り、書き込み、または実行できます。 このアプローチでは、柔軟性とセキュリティの両方が提供され、必要なリソースへのアクセスを許可しながら、信頼されていないアプリケーションや侵害されたアプリケーションから有害な可能性のあるアクションを制限できます。

AppContainers は、他のアプリケーションに属するプロセスやウィンドウへのアクセス、およびデバイス、ファイル/ディレクトリ、レジストリ キー、ネットワーク、資格情報から分離されています。 したがって、信頼されていないデータを安全に解析するなど、潜在的な危険な操作をサンドボックス化するためのメカニズムを提供します。

通常の AppContainers には、特定のシステム ファイル/ディレクトリ、共通レジストリ キー、COM オブジェクトへのアクセス権が付与されますが、LPAC には、通常の AppContainers がアクセスできるリソースにアクセスするための特定の機能が必要です。 低い特権 AppContainers (LPAC) は、通常の AppContainers よりも分離されており、通常の AppContainers がレジストリ、ファイルなどのアクセス権を既に持っているリソースにアクセスするための追加の機能が必要です。 たとえば、LPAC は registryRead 機能を持ち、 lpacCom 機能がない限り COM を使用できない限り、レジストリ内のキーを開くことができません。

AppContainer の起動

前述のように、AppContainers には一意のパッケージ SID があり、独自のリソースが他のアプリケーションから確実に保護されます。 パッケージ SID は、指定された AppContainer の文字列名 (モニカー) から派生します。 AppX マニフェストを介して生成された AppContainers の場合、これはパッケージ ファミリ名 (PFN) ですが、アプリケーションが AppContainer プロセス自体を起動する場合、アプリケーションは AppContainer に付ける名前 (モニカー) を決定する必要があります。

AppContainer を起動するには、いくつかの手順が必要です。 付与に必要な機能を決定する必要があります。AppContainer でファイルの作成/読み取り/書き込みが可能な場所、プロセス属性、スレッド属性を含めて、AppContainer を作成する必要があることを Windows に通知するために、AppContainer のプロファイルを作成する必要があります。

機能の構築

AppContainer (または LPAC) では、ネットワーク、場所、LPAC の場合でもレジストリや COM オブジェクトなど、さまざまなリソースにアクセスする機能が必要な場合があります。 機能の構築は 、DeriveCapabilitySidsFromName API を使用して実現できますが、次のコード例に示す GetCapabilitySidFromName などのヘルパー関数でこの API をラップすることをお勧めします。グループ SID はサービスにのみ使用され、API は 1 つの機能しか返さないためです。

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

プロファイルの作成

CreateAppContainerProfile を呼び出して AppContainer を作成し、LOCALAPPDATA 環境変数または GetAppContainerFolderPath を呼び出して AppContainer からアクセスできるプロファイルを作成します。 新しい AppContainer の場合、これは AppContainer のパッケージ SID も返します。 ただし、既存の AppContainer の場合は、 DeriveAppContainerSidFromAppContainerName API を使用してモニカーからパッケージ SID を派生させる必要があります。 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 の SID を取得する方法を示しています。

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 フィールドが必要です。これにより、オブジェクトの名前空間とトークンを含む AppContainer の環境を作成するように CreateProcess に指示する追加情報が可能になります。 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 プロセスの作成

最後の手順では、前の手順で構築したプロセス/スレッド属性を含むスタートアップ情報を使用してプロセスを起動します。 これには、パッケージ SID、機能 (ある場合) と、LPAC である必要があるかどうかが含まれます。これは、すべてのアプリケーション パッケージをオプトアウトすることによって指定されます。

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

セキュリティ識別子

セキュリティ記述子コンポーネント