다음을 통해 공유


낮은 무결성 수준에서 실행할 애플리케이션 디자인

낮은 무결성 수준에서 애플리케이션 프로세스를 실행하는 쉬운 방법은 실행 프로그램 파일의 무결성 수준을 낮은 무결성으로 설정하는 것입니다. 해당 이미지 파일이 시작되면 애플리케이션 프로세스가 낮은 무결성 수준으로 시작됩니다. 예를 들어 낮은 무결성 프로세스에서 Windows 계산기 애플리케이션을 실행하려는 경우를 가정해 보겠습니다.

낮은 무결성에서 calc.exe 실행하려면

  1. 임시 폴더에 c:\Windows\system32\calc.exe 복사본을 만듭니다.

  2. icacls 프로그램을 사용하여 임시 파일의 무결성 수준(lowcalc.exe)을 icacls 명령을 사용하여 낮은 무결성으로 설정합니다.

    icacls lowcalc.exe /setintegritylevel Low

  3. 낮은 무결성 버전의 calc.exe 실행합니다.

다음 이미지는 낮은 무결성 프로세스에서 Windows 계산기를 실행하는 단계를 보여줍니다.

그림 9 낮은 무결성에서 Windows 계산기 시작

프로세스 Explorer 사용하여 lowcalc.exe 이미지 파일이 실제로 낮은 무결성으로 실행되고 있는지 확인할 수 있습니다. 무결성 수준 열은 이미지의 오른쪽에 있습니다.

그림 10 낮은 계산기 프로세스

모든 애플리케이션 프로그램이 낮은 무결성 프로세스에서 제대로 실행되는 것은 아닙니다. 낮은 무결성 프로세스는 파일 시스템의 사용자 로컬 프로필 영역 또는 HKCU의 레지스트리 아래에 있는 대부분의 영역에 대한 쓰기 권한이 없습니다. 프로그램이 원치 않는 악성 소프트웨어인 경우 낮은 무결성 프로세스에서 사용자 프로필에 대한 쓰기 액세스 권한을 얻을 수 없다는 것은 좋은 일입니다. 그러나 보호 모드 인터넷 Explorer 같은 애플리케이션의 경우 애플리케이션의 모든 기능이 올바르게 작동하도록 일부 재설계가 필요할 수 있습니다.

Sysinternals.com 프로세스 모니터와 같은 유용한 도구를 사용하여 애플리케이션이 낮은 무결성으로 실행할 때 실패할 쓰기 액세스에 현재 사용하는 파일 및 레지스트리 리소스를 파악할 수 있습니다.

애플리케이션을 완전히 낮은 무결성으로 실행하도록 변경할 수 있지만 애플리케이션의 일부 기능은 중간 무결성 프로세스에서 구현된 경우에만 제대로 작동할 수 있습니다. 낮은 무결성으로 실행되는 애플리케이션은 인터넷에서 신뢰할 수 없는 데이터를 처리하는 것과 같이 낮은 무결성 프로세스에서 애플리케이션의 한 부분을 가질 수 있습니다. 애플리케이션의 다른 부분은 중간 무결성 "broker" 프로세스에서 구현하여 사용자가 시작한 작은 작업 집합을 처리할 수 있습니다. 애플리케이션의 낮은 무결성 및 중간 무결성 프로세스 간의 통신은 다양한 IPC 메커니즘을 사용하여 처리할 수 있습니다. 애플리케이션의 중간 무결성 부분은 낮은 무결성 프로세스의 모든 데이터와 코드가 신뢰할 수 없다고 가정해야 합니다.

보호 모드 인터넷 Explorer 낮은 무결성 프로세스에서 실행되도록 다시 디자인된 하나의 애플리케이션입니다. 보호 모드 인터넷 Explorer 대한 자세한 내용은 보호 모드 인터넷 Explorer 이해 및 작업(https://go.microsoft.com/fwlink/?LinkId=90931)을 참조하세요.

낮은 무결성으로 실행되도록 애플리케이션을 디자인하는 기본 topics 다음과 같습니다.

  • 낮은 무결성에서 자식 프로세스 시작
  • 낮은 무결성 애플리케이션을 위한 쓰기 가능한 위치
  • 낮은 무결성과 상위 수준 프로세스 간의 통신

낮은 무결성으로 프로세스 시작

기본적으로 자식 프로세스는 부모 프로세스의 무결성 수준을 상속합니다. 낮은 무결성 프로세스를 시작하려면 CreateProcessAsUser 함수를 사용하여 낮은 무결성 액세스 토큰으로 새 자식 프로세스를 시작해야 합니다. 중간 무결성 프로세스에서 낮은 무결성 프로세스를 시작하려면 새 프로세스를 낮은 무결성으로 명시적으로 시작해야 합니다.

낮은 무결성 프로세스를 시작하려면

  1. 중간 무결성 수준인 현재 프로세스의 핸들을 복제합니다.

  2. SetTokenInformation을 사용하여 액세스 토큰의 무결성 수준을 낮음으로 설정합니다.

  3. CreateProcessAsUser를 사용하여 낮은 무결성 액세스 토큰에 대한 핸들을 사용하여 새 프로세스를 만듭니다.

CreateProcessAsUser는 새 자식 프로세스의 보안 설명자와 낮은 무결성 액세스 토큰의 무결성 수준과 일치하도록 액세스 토큰에 대한 보안 설명자를 업데이트합니다.

다음 코드 샘플에서는 이 프로세스를 보여 줍니다.

void CreateLowProcess()
{
 
    BOOL                  fRet;
    HANDLE                hToken        = NULL;
    HANDLE                hNewToken     = NULL;
    PSID                  pIntegritySid = NULL;
    TOKEN_MANDATORY_LABEL TIL           = {0};
    PROCESS_INFORMATION   ProcInfo      = {0};
    STARTUPINFO           StartupInfo   = {0};

 // Notepad is used as an example
 WCHAR wszProcessName[MAX_PATH] =
   L"C:\\Windows\\System32\\Notepad.exe";

 // Low integrity SID
 WCHAR wszIntegritySid[20] = L"S-1-16-1024";
 PSID pIntegritySid = NULL;

    fRet = OpenProcessToken(GetCurrentProcess(),
                            TOKEN_DUPLICATE |
                              TOKEN_ADJUST_DEFAULT |
                              TOKEN_QUERY |
                              TOKEN_ASSIGN_PRIMARY,
                            &hToken);

    if (!fRet)
    {
        goto CleanExit;
    }

    fRet = DuplicateTokenEx(hToken,
                            0,
                            NULL,
                            SecurityImpersonation,
                            TokenPrimary,
                            &hNewToken);

    if (!fRet)
    {
        goto CleanExit;
    }

    fRet = ConvertStringSidToSid(wszIntegritySid, &pIntegritySid);

    if (!fRet)
    {
        goto CleanExit;
    }

    TIL.Label.Attributes = SE_GROUP_INTEGRITY;
    TIL.Label.Sid        = pIntegritySid;

    //
    // Set the process integrity level
    //

    fRet = SetTokenInformation(hNewToken,
                               TokenIntegrityLevel,
                               &TIL,
                               sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(pIntegritySid));

    if (!fRet)
    {
        goto CleanExit;
    }

    //
    // Create the new process at Low integrity
    //

    fRet  = CreateProcessAsUser(hNewToken,
                                NULL,
                                wszProcessName,
                                NULL,
                                NULL,
                                FALSE,
                                0,
                                NULL,
                                NULL,
                                &StartupInfo,
                                &ProcInfo);

CleanExit:

    if (ProcInfo.hProcess != NULL)
    {
        CloseHandle(ProcInfo.hProcess);
    }

    if (ProcInfo.hThread != NULL)
    {
        CloseHandle(ProcInfo.hThread);
    }

    LocalFree(pIntegritySid);

    if (hNewToken != NULL)
    {
        CloseHandle(hNewToken);
    }

    if (hToken != NULL)
    {
        CloseHandle(hToken);
    }

    return fRet;
}

낮은 무결성의 쓰기 가능한 위치

Windows Vista에는 낮은 무결성 애플리케이션 쓰기 액세스를 허용하기 위해 낮은 필수 레이블이 할당된 특정 파일 및 레지스트리 위치가 있습니다. 표 10에는 이러한 쓰기 가능한 위치가 표시됩니다.

낮은 필수 레이블에 대해 쓸 수 있는 표 10 위치

위치 쓰기 가능한 영역

레지스트리

낮은 무결성 프로세스는 HKEY_CURRENT_USER\Software\AppDataLow 아래에 하위 키에 쓰고 만들 수 있습니다.

파일 시스템

무결성이 낮은 프로세스는 %USER PROFILE%\AppData\LocalLow에서 하위 폴더를 작성하고 만들 수 있습니다.

리소스 필수 레이블 낮추기

잠재적인 보안 위험으로 인해 입력을 수락하거나 낮은 무결성 프로세스와 리소스를 공유하도록 더 높은 무결성 프로세스를 설계하지 않는 것이 좋습니다. 무결성이 낮은 프로세스는 악의적인 동작을 시도할 수 있습니다. 그러나 의도적으로 이 작업을 수행해야 할 수 있습니다.

참고

하위 무결성 프로세스에서 입력을 수락하거나 리소스를 공유하는 애플리케이션은 낮은 무결성 프로세스가 제공하는 데이터를 신뢰할 수 없다고 가정하고 적절한 유효성 검사를 수행해야 합니다. 예를 들어 보호 모드 인터넷 Explorer Internet Explorer User Broker 프로세스의 다른 이름으로 저장 대화 상자를 표시합니다. 이렇게 하면 사용자가 보호 모드 인터넷 Explorer보다 높은 권한으로 실행되는 프로세스를 사용하여 파일을 저장하려는지 확인할 수 있습니다.

낮은 무결성 애플리케이션은 낮은 무결성 리소스에만 쓸 수 있으므로 공유 리소스의 무결성 수준을 낮춰야 합니다.

공유 리소스의 무결성 수준을 낮추려면

  1. 낮은 필수 레이블을 정의하는 SDDL 보안 설명자를 만듭니다.

  2. SDDL 문자열을 보안 설명자로 변환합니다.

  3. 낮은 무결성 특성을 보안 설명자에 할당합니다.

  4. 공유 리소스에 보안 설명자를 할당합니다.

다음 코드 샘플에서는 이 프로세스를 보여줍니다.

#include <sddl.h>
#include <AccCtrl.h>
#include <Aclapi.h>

void SetLowLabelToFile()
{
 // The LABEL_SECURITY_INFORMATION SDDL SACL to be set for low integrity 
 #define LOW_INTEGRITY_SDDL_SACL_W L"S:(ML;;NW;;;LW)"
 DWORD dwErr = ERROR_SUCCESS;
 PSECURITY_DESCRIPTOR pSD = NULL;  

 PACL pSacl = NULL; // not allocated
 BOOL fSaclPresent = FALSE;
 BOOL fSaclDefaulted = FALSE;
 LPCWSTR pwszFileName = L"Sample.txt";

 if (ConvertStringSecurityDescriptorToSecurityDescriptorW(
     LOW_INTEGRITY_SDDL_SACL_W, SDDL_REVISION_1, &pSD, NULL)) 
 {
  if (GetSecurityDescriptorSacl(pSD, &fSaclPresent, &pSacl, 
     &fSaclDefaulted))
  {
   // Note that psidOwner, psidGroup, and pDacl are 
   // all NULL and set the new LABEL_SECURITY_INFORMATION
   dwErr = SetNamedSecurityInfoW((LPWSTR) pwszFileName, 
         SE_FILE_OBJECT, LABEL_SECURITY_INFORMATION, 
         NULL, NULL, NULL, pSacl);
  }
  LocalFree(pSD);
 }
}

애플리케이션 프로세스는 보안 개체의 무결성을 애플리케이션 프로세스의 무결성 수준 이하 수준으로만 설정할 수 있습니다.

낮은 무결성과 더 높은 무결성 프로세스 간의 통신

낮은 무결성 프로세스는 다른 애플리케이션과 완전히 격리되지 않습니다. 다른 프로세스와 상호 작용할 수 있습니다. 실제로 일부 형태의 협업이 없으면 낮은 무결성으로 실행되는 애플리케이션이 사용자에게 완전히 손상되는 것처럼 보일 수 있습니다.

일부 형태의 IPC는 낮은 무결성 프로세스에서 더 높은 무결성 프로세스와 통신하는 데 사용할 수 있습니다. Windows Vista의 구성 요소는 다음과 같은 유형의 통신을 차단합니다.

  • 대부분의 창 메시지 및 프로세스 후크는 UIPI에 의해 차단됩니다.

  • 프로세스를 열고 CreateRemoteThread를 사용하는 것은 프로세스 개체의 필수 레이블에 의해 차단됩니다.

  • 쓰기 액세스에 대한 공유 메모리 섹션 열기가 차단됩니다.

  • 동기화를 위해 더 높은 무결성 프로세스에서 만든 명명된 개체를 사용하는 것은 기본 필수 레이블에 의해 차단됩니다.

  • COM 서비스의 실행 중인 instance 바인딩은 차단됩니다.
    그러나 낮은 무결성 프로세스와 더 높은 무결성 프로세스 간에 다른 유형의 통신을 사용할 수 있습니다. 사용할 수 있는 통신 유형은 다음과 같습니다.

  • 클립보드(복사 및 붙여넣기)

  • RPC(원격 프로시저 호출)(Remote procedure call (RPC))

  • 소켓

  • 더 높은 무결성 프로세스가 ChangeWindowMessageFilter를 호출하여 낮은 무결성 프로세스에서 명시적으로 수신하도록 허용된 창 메시지

  • 공유 메모리- 높은 무결성 프로세스가 공유 메모리 섹션의 필수 레이블을 명시적으로 낮춥니다.

    중요

    이는 특히 위험하며, 무결성이 높은 프로세스는 공유 섹션에 기록된 모든 데이터의 유효성을 검사하기 위해 주의해야 합니다.

  • COM 인터페이스- 낮은 무결성 클라이언트에서 바인딩할 수 있도록 더 높은 무결성 프로세스에 의해 시작 활성화 권한이 프로그래밍 방식으로 설정됩니다.

  • 명명된 파이프- 작성자가 낮은 무결성 프로세스에 대한 액세스를 허용하도록 파이프의 필수 레이블을 명시적으로 설정합니다.

이러한 통신 메커니즘을 사용하면 낮은 무결성 프로세스가 브로커 프로세스와 같은 다른 애플리케이션 프로세스와 상호 작용할 수 있으며, 이는 낮은 무결성 원본의 입력 또는 호출을 허용하도록 특별히 설계되었습니다.

낮은 무결성 프로세스에서 호출할 인터페이스를 디자인하기 위한 일반적인 지침은 호출자 또는 입력 데이터를 신뢰하지 않는 것입니다. 중간 무결성 브로커는 경로가 지정된 파일을 만들고 낮은 무결성 애플리케이션이 인터페이스를 호출할 수 있도록 하는 인터페이스를 제공할 수 있습니다. 그러나 이렇게 하면 낮은 무결성으로 앱을 실행하는 목적이 무효화됩니다. 더 나은 디자인은 낮은 무결성 프로세스가 중간 무결성 애플리케이션이 사용자에게 공통 파일 대화 상자를 표시하도록 요청하는 인터페이스를 호출하는 것입니다. 이 인터페이스는 낮은 무결성 프로세스가 창 메시지를 사용하여 구동할 수 없습니다. 이렇게 하면 사용자가 열거나 만들 파일을 찾아서 선택할 수 있으며 중간 무결성 프로세스는 모든 파일 작업을 수행합니다. 이 유형의 다른 이름으로 저장 시나리오는 보호 모드 인터넷 Explorer 자체 broker 프로세스를 사용하여 사용자 프로필의 어딘가에 웹 페이지 저장을 처리하는 방법의 예입니다.

많은 애플리케이션 기능은 낮은 무결성 프로세스에서 올바르게 실행할 수 있습니다. 낮은 무결성에서 애플리케이션을 실행하기 위한 일반적인 도구 집합은 없습니다. 각 애플리케이션은 다르며 모든 애플리케이션을 낮은 무결성으로 실행해야 하는 것은 아닙니다.