Meluncurkan AppContainer

Artikel ini menjelaskan langkah-langkah yang diperlukan untuk meluncurkan AppContainer atau Less-Privileged AppContainer termasuk contoh kode yang relevan. AppContainers adalah fitur keamanan yang diperkenalkan di Windows 8 untuk meningkatkan isolasi dan kontrol proses aplikasi. Mereka menyediakan lingkungan terkotakpasir untuk aplikasi, membatasi kemampuan mereka untuk mengakses sistem atau sumber daya satu sama lain, serta data pengguna kecuali diizinkan secara eksplisit. AppContainers memanfaatkan mekanisme keamanan Windows yang ada, seperti pengidentifikasi keamanan (SID), token, dan daftar kontrol akses diskresi deskriptor keamanan (DACL), untuk menerapkan pembatasan ini.

Terminologi

Tabel berikut menentukan istilah dan konsep yang dirujuk dalam artikel ini.

Istilah Description
Identitas paket Identitas paket adalah konstruksi logis, secara unik mengidentifikasi paket. Untuk informasi selengkapnya, lihat Gambaran umum Identitas Paket di aplikasi Windows.
Pengidentifikasi keamanan (SID) SID digunakan untuk mengidentifikasi prinsip keamanan atau kelompok keamanan secara unik. Prinsip keamanan dapat mewakili entitas apa pun yang dapat diautentikasi oleh sistem operasi. Contohnya termasuk akun pengguna, akun komputer, atau utas atau proses yang berjalan dalam konteks keamanan pengguna atau akun komputer. Untuk informasi selengkapnya, lihat Pengidentifikasi keamanan
SID kapabilitas SID kemampuan berfungsi sebagai pengidentifikasi unik dan tidak dapat diubah untuk kemampuan. Kemampuan mewakili token otoritas yang tidak terlupakan yang memberikan akses aplikasi ke sumber daya (misalnya, dokumen, kamera, dan lokasi). Untuk informasi selengkapnya, lihat Deklarasi kemampuan aplikasi
Daftar Kontrol Akses Diskresi (DACL) Daftar yang mengidentifikasi pengguna dan grup yang dapat melakukan berbagai operasi pada objek. Untuk informasi selengkapnya, lihat Komponen pendeskripsi keamanan.
AppContainers Dengan Hak Istimewa Lebih Sedikit (LPAC) Jenis AppContainer yang lebih terisolasi daripada AppContainer biasa. Ini memerlukan deklarasi kemampuan eksplisit untuk mengakses sumber daya yang dapat diakses oleh AppContainers.

Gambaran umum AppContainer

Saat aplikasi berjalan sebagai AppContainer, token aksesnya menyertakan identitas paket aplikasi unik (Package SID) dan satu atau beberapa SID kemampuan. Untuk AppContainers, kemampuan digunakan untuk memastikan bahwa AppContainers dapat berjalan dengan hak istimewa sekecil mungkin dan hanya diberikan akses ke sumber daya yang berpotensi sensitif jika diperlukan. Misalnya, tanpa kemampuan jaringan , AppContainer tidak dapat mengakses jaringan, tanpa kemampuan webcam , appContainer tidak dapat mengakses kamera. SID AppContainer (SID Paket dan Kemampuan) terpisah dari SID pengguna dan grup tradisional dengan kedua bagian token yang diperlukan untuk memberikan akses ke sumber daya yang dilindungi melalui daftar kontrol akses diskresi objek (DACL). Model dual-principal ini memastikan bahwa akses ke sumber daya sensitif dikontrol dengan ketat dan dapat dikelola secara independen untuk aplikasi yang berbeda. Ini juga memastikan bahwa AppContainers harus secara eksplisit diberikan akses ke sumber daya tertentu. Selain itu, akses yang diizinkan adalah persimpangan yang diberikan oleh SID pengguna/grup dan SID AppContainer sehingga jika Pengguna memiliki akses penuh, tetapi AppContainer hanya memiliki akses baca, AppContainer hanya dapat diberikan akses baca. Demikian pula, jika pengguna telah membaca & menjalankan akses tetapi AppContainer memiliki akses penuh AppContainer hanya dapat diberikan akses baca & jalankan.

AppContainers berjalan dengan Tingkat Integritas Rendah (IL), yang semakin membatasi kemampuan mereka untuk berinteraksi dengan objek integritas yang lebih tinggi pada sistem. Namun, jika sumber daya memiliki label wajib MEDIUM IL atau lebih rendah dan DACL memberikan akses melalui ke AppContainer (melalui Package SID atau Capability SID) maka AppContainer dapat membaca, menulis, atau menjalankan tergantung pada akses yang diberikan kepada kedua prinsipal di DACL. Pendekatan ini memberikan fleksibilitas dan keamanan, memungkinkan akses ke sumber daya yang diperlukan sambil membatasi tindakan yang berpotensi berbahaya dari aplikasi yang tidak tepercaya atau disusupi.

AppContainers diisolasi dari mengakses proses dan jendela milik aplikasi lain serta dari perangkat, file/direktori, kunci registri, jaringan, dan kredensial. Dengan demikian, mereka menyediakan mekanisme untuk sandboxing potensi operasi berisiko seperti mengurai data yang tidak tepercaya dengan aman.

AppContainers reguler diberikan akses ke file/direktori sistem tertentu, kunci registri umum, dan objek COM, namun, LPAC memerlukan kemampuan khusus untuk mengakses sumber daya yang dapat diakses AppContainers reguler. Less Privileged AppContainers (LPAC) bahkan lebih terisolasi daripada AppContainers reguler dan memerlukan kemampuan lebih lanjut untuk mendapatkan akses ke sumber daya yang sudah dapat diakses oleh AppContainers reguler seperti registri, file, dan lainnya. Misalnya, LPAC tidak dapat membuka kunci apa pun dalam registri kecuali memiliki kemampuan registriRead dan tidak dapat menggunakan COM kecuali memiliki kemampuan lpacCom .

Meluncurkan AppContainer

Seperti disebutkan sebelumnya, AppContainers memiliki SID Paket unik yang memastikan bahwa sumber daya mereka sendiri dilindungi dari aplikasi lain. SID Paket berasal dari nama string (moniker) untuk AppContainer yang diberikan. Dalam kasus AppContainers yang diluncurkan melalui manifes AppX, ini adalah Nama Keluarga Paket (PFN) tetapi dalam kasus aplikasi meluncurkan proses AppContainer itu sendiri, aplikasi perlu menentukan nama (moniker) yang ingin diberikan kepada AppContainer.

Ada beberapa langkah yang terlibat dalam meluncurkan AppContainer. Kemampuan yang diperlukan untuk diberikan perlu ditentukan, profil perlu dibuat untuk AppContainer sehingga ada lokasi di mana AppContainer dapat membuat/membaca/menulis file, proses dan atribut utas perlu disertakan untuk memberi tahu Windows bahwa itu perlu membuat AppContainer.

Membangun kemampuan

AppContainer (atau LPAC) mungkin memerlukan kemampuan untuk mengakses sumber daya yang berbeda seperti jaringan, lokasi, atau dalam kasus LPAC bahkan registri atau objek COM. Membangun kemampuan dapat dicapai melalui DeriveCapabilitySidsFromName API, meskipun lebih baik untuk membungkus API ini dalam fungsi pembantu, seperti GetCapabilitySidFromName yang ditampilkan dalam contoh kode di bawah ini, karena SID Grup hanya digunakan untuk layanan dan API hanya pernah mengembalikan satu kemampuan.

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

Contoh kode berikut menunjukkan penggunaan fungsi pembantu GetCapabilitySidFromName yang ditentukan dalam contoh sebelumnya untuk membangun kemampuan internetClient dan lokasi .

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

Membuat Profil

Buat AppContainer dengan memanggil CreateAppContainerProfile, dengan profil dapat diakses oleh AppContainer melalui variabel lingkungan LOCALAPPDATA atau dengan memanggil GetAppContainerFolderPath. Untuk AppContainer baru, ini juga mengembalikan SID Paket untuk AppContainer. Namun, untuk AppContainer yang ada, perlu untuk mendapatkan SID paket dari moniker menggunakan Api DeriveAppContainerSidFromAppContainerName . Variabel lingkungan TMP dan TEMP juga dialihkan ke direktori yang dapat diakses oleh AppContainer di bawah lokasi profil:

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

Contoh kode berikut menunjukkan penggunaan fungsi CreateAppContainerProfile untuk membuat profil AppContainer dan mengambil SID untuk AppContainer baru atau yang sudah ada.

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

Meluncurkan AppContainer (atau LPAC)

Untuk meluncurkan proses AppContainer atau LPAC, perlu untuk menyertakan bidang tertentu dalam struktur informasi startup, STARTUPINFOEX. Khususnya bidang lpAttributeList diperlukan karena ini memungkinkan informasi tambahan yang menginstruksikan CreateProcess untuk membuat lingkungan untuk AppContainer yang mencakup namespace dan token objek. Bidang lpAttributeList berjenis LPPROC_THREAD_ATTRIBUTE_LIST dan disiapkan sebagai berikut.

Contoh berikut menunjukkan cara meluncurkan kontainer aplikasi reguler.

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; 

Contoh berikut menunjukkan cara meluncurkan AppContainer (LPAC) yang kurang istimewa, yang memerlukan atribut proses/utas tambahan:

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; 

Membuat proses AppContainer/LPAC

Langkah terakhir adalah meluncurkan proses menggunakan informasi startup, yang mencakup atribut proses/utas yang dibangun pada langkah-langkah sebelumnya. Ini akan mencakup paket SID, kemampuan, jika ada, serta jika ini harus menjadi LPAC, yang ditentukan dengan memilih keluar dari Semua Paket Aplikasi.

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

Pengidentifikasi keamanan

Komponen deskriptor keamanan