「같은 PC」는 같은 실행 환경이 아니다 ── AppData·HKCU·DPAPI·자격 증명을 가르는 사용자 경계

· 업데이트: · · Windows, DPAPI, 레지스트리, AppData, 자격 증명, 작업 스케줄러

수정 이력(초판, 2026년 08월 28일 공개)
최초 공개

탐색기에서 실행하면 설정 파일을 읽는데 작업 스케줄러에서는 「찾을 수 없다」고 한다. 서비스로 만들면 저장한 비밀번호를 복호화하지 못한다. 내 PC의 브라우저는 로그인되어 있는데 CI에서는 로그인 화면으로 돌아간다.

이런 종류의 문제에서는 코드보다 먼저 「누구로서, 어떻게 실행하고 있는가」를 확인합니다. 같은 PC에 있는 파일이나 설정이라도 다른 실행 사용자에게서 똑같이 쓸 수 있다고는 할 수 없기 때문입니다.

이 글의 물음은 코드를 바꾸지 않았는데 작업화·서비스화·CI화를 했다는 것만으로 앱이 망가지는 이유는 무엇인가입니다. 증상에서부터 조사하고 싶다면 다음 표에서 해당하는 곳으로 이동하십시오.

증상 가장 먼저 비교할 것 읽을 곳
설정 파일이나 명령을 찾을 수 없다 실행 사용자, AppData의 실제 경로, 사용자 환경 변수 AppData와 환경 변수
분명히 쓴 레지스트리 값이 없다 HKCU가 가리키는 사용자의 하이브 HKCU
파일은 읽히는데 비밀 정보를 복호화할 수 없다 DPAPI의 스코프와 마스터 키의 주인 DPAPI
브라우저의 로그인 상태를 이어받을 수 없다 실행 사용자, 프로필, DPAPI로 보호된 키 브라우저 프로필
저장된 자격 증명이나 인증서를 쓸 수 없다 실행 계정의 금고와 인증서 저장소, 작업의 로그온 유형 자격 증명과 인증서
관리자로 실행하면 Z: 드라이브가 없다 권한 상승 전후의 토큰과 로그온 세션 UAC 권한 상승
이전 전에 전반적으로 점검하고 싶다 실행 형태별 의존 대상과 셋업 실행 형태별 체크리스트, 조사 절차

이 글의 전제

항목 내용
대상 독자 업무 앱을 서비스화·작업화·CI화하는 개발자와 「내 PC에서는 동작하는데」를 조사하는 운영 담당자
전제 환경 Windows 10/11. 검증 코드는 PowerShell 5.1 이상에서 실행한다
난이도 중급

1. 먼저 결론부터

Windows의 실행 환경을 가르는 기본 단위는 PC가 아니라 액세스 토큰과 SID, 즉 「누구로서 동작하고 있는가」입니다.AppData·HKCU·DPAPI의 키·브라우저 프로필·자격 증명은 그 사용자의 환경에 속합니다.

대화형 로그온한 자신이 준비한 설정이나 로그인 상태는 SYSTEM이나 다른 서비스 계정으로 자동으로 이어지지 않습니다. 머신 전체의 데이터를 두는 영역은 ProgramDataHKLM이며, 공유하는 경우에도 액세스 권한의 설계가 필요합니다.

같은 PC 안의 두 세계같은 PC는 HKLM과 ProgramData만 공유하고, 여러분의 SID의 세계와 다른 SID의 세계가 각각 고유한 AppData, 레지스트리 하이브, DPAPI 키를 가지며, 사용자 경계로 서로 보이지 않는다사용자 경계:서로 보이지 않는다같은 PC공유:HKLM, ProgramData여러분의 SID의 세계다른 SID의 세계 (SYSTEM 등)AppData, HKCU, DPAPI 키다른 AppData, 다른 하이브, 다른 키

그림 1: 같은 PC라도 실행 사용자가 다르면 AppData, 레지스트리, 키는 별개의 것이 됩니다.

다만 SID가 같다고 해서 반드시 같은 환경이 되는 것도 아닙니다.작업의 로그온 유형, IIS의 프로필 로드, UAC 권한 상승에 따른 로그온 세션의 차이도 확인합니다. 같은 계정의 권한 상승으로 HKCU나 금고까지 다른 사용자의 것이 되는 것은 아니므로, 달라지는 경계를 나누어 생각하는 것이 중요합니다.

아래는 전제가 되는 실행 사용자 (2장), 다섯 개의 경계 (3~7장), 실행 형태별 점검 (8장), 설계와 조사 (9장)의 순서입니다.

그림의 실선은 항상 성립하는 관계, 점선은 조건이 붙는 관계입니다(성립 조건은 상세 페이지의 관계별 설명에 적혀 있습니다). 관계 전체 목록(총 33건, 근거와 확신도 포함)과 주요 개념의 정의는 지식 맵 상세 페이지에 정리되어 있습니다(일본어). 데이터: JSON-LD / Turtle

2. 전제: 「누구로서 동작하는가」가 모든 것을 결정한다

2.1 사용자 이름이 아니라 SID와 토큰을 확인한다

Windows가 사용자를 식별하는 ID는 사용자 이름이 아니라 SID (보안 식별자)입니다. 프로세스는 액세스 토큰을 가지며 그 안에 실행 사용자의 SID가 들어 있습니다. 파일의 ACL 판정, 레지스트리의 실체, 암호 키를 생각할 때도 이 실행 주체가 출발점이 됩니다.

첫 확인에는 whoami /user를 사용합니다. 자기 터미널의 결과가 아니라 문제가 일어나는 실행 환경에서의 결과를 확인합니다.

> whoami /user

사용자 정보
----------------

사용자 이름     SID
=============== =============================================
desktop\you     S-1-5-21-3623811015-3361044348-30300820-1001

C:\Users\you는 그 SID에 연결된 사용자 프로필의 실체입니다. 프로필에는 AppData 등의 폴더들과 사용자 레지스트리 하이브 NTUSER.DAT가 있습니다. 첫 로그온 시에 기본 프로필에서 복제되므로, 다른 사용자의 프로필은 자신이 설정을 갖춰 놓은 환경과는 다른 초기 상태에서 시작합니다.1

시작 경로에서 프로필까지의 흐름더블 클릭, 작업 스케줄러, 서비스나 IIS 중 어느 경로로 시작하더라도 프로세스는 액세스 토큰의 SID를 가지며, 그 SID에 연결된 사용자 프로필 일체가 실행 환경이 된다더블 클릭프로세스의 토큰 (SID)작업 스케줄러서비스, IISSID에 연결된 프로필 일체SID가 다르면 초기 상태의 다른 프로필

그림 2: 어느 경로로 시작되는지가 어느 SID의 프로필을 짊어지고 동작할지를 결정합니다.

2.2 서비스용 계정에도 각각의 환경이 있다

Windows에는 사람이 로그온하지 않아도 동작하는 기본 제공 계정이 있습니다. 각각이 독립된 실행 환경을 가집니다.2

계정 SID 프로필·레지스트리의 참조 대상
SYSTEM (LocalSystem) S-1-5-18 프로필은 C:\Windows\System32\config\systemprofile 하위. HKCU는 기본 사용자에 연결된다3
LocalService S-1-5-19 C:\Windows\ServiceProfiles\LocalService 하위. HKEY_USERS에 자신의 하위 키를 가진다4
NetworkService S-1-5-20 C:\Windows\ServiceProfiles\NetworkService 하위. LocalService와 마찬가지로 자신의 프로필과 하이브를 가진다4
IIS AppPool\<이름> S-1-5-82-… 풀 전용 ID. 프로필은 기본적으로 로드되지 않는다5

더블 클릭, 작업 스케줄러, 서비스, IIS라는 시작 경로의 차이는 어느 실행 주체의 환경을 쓰는가의 차이로 이어집니다. 자신의 대화형 로그온에서 준비한 설정·키·자격 증명이 그 실행 대상에도 있다고 생각하지 마십시오.

2.3 「같은 사용자」 다음으로 확인할 세 가지 조건

확인할 조건 차이가 드러나는 예
로그온 유형 작업의 S4U 로그온에서는 암호를 저장하지 않으며 네트워크나 EFS에 액세스할 수 없다6
프로필의 로드 IIS에서는 loadUserProfile에 따라 AppData나 사용자 하이브를 쓸 수 있는지가 달라진다7
로그온 세션과 권한 상승 같은 SID라도 권한 상승한 프로세스에서 네트워크 드라이브가 보이지 않는 경우가 있다89

SID 확인으로 끝내지 말고 「같은 계정이라도 무엇이 다른가」를 이 세 가지로 정리합니다. 작업은 8장, IIS는 4~5장, 권한 상승은 7장에서 자세히 봅니다.

3. 경계 1: AppData ── 같은 환경 변수가 다른 곳을 가리킨다

전형적인 증상은 작업으로 만들자마자 설정 파일을 찾을 수 없게 되는 것입니다.경로 해석에 실패하고 있는 것이 아니라, 다른 사용자의 올바른 경로로 해석되고 거기에 파일이 없는 경우가 있습니다.

3.1 AppData의 구분과 실행 사용자에 따른 차이

AppData는 사용자 프로필 하위의 폴더입니다. 용도는 다음과 같이 나뉩니다.10

영역 주된 용도
%APPDATA% (Roaming) 프로필의 이동에 따라가게 하고 싶은 사용자 설정
%LOCALAPPDATA% (Local) 머신 로컬한 데이터나 캐시
AppData\LocalLow 낮은 무결성 수준의 프로세스용 데이터

같은 코드로 %APPDATA%를 열어도 실행 사용자에 따라 참조 대상은 달라집니다.

실행 사용자 설정 파일을 찾는 위치의 예
사용자 A C:\Users\a\AppData\Roaming\MyApp
SYSTEM systemprofile 하위의 AppData

사용자 A가 저장한 파일은 SYSTEM 쪽에는 존재하지 않습니다. 「설정 파일이 없다」는 오류만으로는 알기 어려우므로, 조사에서는 환경 변수 이름이 아니라 실제로 연 경로를 봅니다.

%APPDATA%의 해석은 사용자에 따라 달라진다같은 코드가 %APPDATA%를 열어도 실행 사용자가 여러분이면 C:\Users 하위로, SYSTEM이면 systemprofile 하위로 해석되며 후자에는 여러분의 설정 파일이 존재하지 않는다여러분SYSTEM같은 코드:%APPDATA%를 연다실행 사용자는?C:\Users\you\AppData\Roamingsystemprofile 하위의 AppData두었을 터인 파일이 없다

그림 3: 환경 변수는 거짓말을 하지 않지만 해석 결과는 토큰에 따라 달라집니다.

3.2 PATH에도 사용자별 차이가 있다

시스템 환경 변수는 머신 공유이지만 사용자 환경 변수는 사용자마다 따로입니다. 자신의 PATH에 추가한 명령을 서비스에서 찾지 못하는 경우에도 이 차이를 확인합니다.

저장 위치는 「누가 읽는 데이터인가」로 정합니다. 그 사용자만의 설정은 AppData에, 모든 사용자나 서비스가 공유하는 데이터는 %ProgramData% 하위에 두고 후자는 ACL을 설계합니다. 자세한 고르는 법은 「Windows 앱 데이터 저장 위치 고르기 ── SQLite / JSON / 레지스트리 / Access 판단표」를 참조하십시오.

저장 위치는 독자가 정한다그 사용자만 읽는 데이터는 AppData나 HKCU에, 모든 사용자나 서비스와 공유하는 데이터는 ProgramData나 HKLM에 두며 후자는 ACL 설계를 동반한다그 사용자만모든 사용자, 서비스그 데이터를 읽는 것은 누구인가AppData, HKCUProgramData, HKLM장래에 서비스화한다면 재검토쓰기 권한과 ACL을 설계한다

그림 4: 「서비스로 만들었더니 읽지 못한다」는 설계 시에 이 분기를 건너뛴 결과입니다.

4. 경계 2: HKCU ── 「현재 사용자」는 호출한 쪽에 따라 달라진다

전형적인 증상은 설치 프로그램이 쓴 라이선스 정보를 서비스에서 찾지 못하는 것입니다.쓴 곳과 읽은 곳이 둘 다 HKCU라는 이름이더라도 같은 실체라고는 할 수 없습니다.

4.1 HKCU는 사용자의 하이브에 대한 별칭

HKEY_CURRENT_USER (HKCU)는 독립된 하이브가 아니라 호출한 쪽의 사용자에 따라 실체로 바꿔 연결되는 별칭입니다. 일반적인 사용자 프로세스에서는 HKEY_USERS 하위의 그 SID의 키를 가리킵니다. 그 내용은 로그온 시에 로드된 NTUSER.DAT입니다.1

예외는 HKCU\Software\Classes로, 실체는 별개의 하이브 파일 UsrClass.dat입니다. 이 파일은 %LOCALAPPDATA%\Microsoft\Windows 하위에 놓입니다.11

LocalSystem의 HKCU는 기본 사용자 (HKEY_USERS\.DEFAULT)에 연결됩니다. 관리자 계정으로 실행한 설치 프로그램이 HKCU에 쓰고 SYSTEM의 서비스가 HKCU에서 읽으면 참조 대상이 어긋납니다.3

HKCU라는 별칭의 실체앱이 HKCU를 열면 여러분의 프로세스에서는 HKEY_USERS 하위의 여러분의 SID 키로, LocalSystem의 프로세스에서는 기본 사용자의 키로 바꿔 연결되어 설치 프로그램이 쓴 값이 보이지 않게 된다여러분의 프로세스SYSTEM의 프로세스앱의 코드:HKCU를 연다HKCU는 실체에 대한 별칭HKEY_USERS 하위의 여러분의 SIDHKEY_USERS\.DEFAULT썼을 터인 값이 존재하지 않는다

그림 5: HKCU라는 같은 이름을 써도 사용자가 바뀌면 읽고 쓰는 실체가 바뀝니다.

머신 전체의 설정은 HKLM에 둡니다. Microsoft는 서비스에서 HKCU에 액세스하는 것을 권장하지 않습니다. 사용자의 설정을 읽어야 한다면 그 사용자를 가장 (impersonation)한 뒤에 RegOpenCurrentUser를 사용합니다.12

4.2 프로필이 로드되어 있는지도 확인한다

실행 계정에 더해 프로필이 로드되어 있는지가 문제가 되는 경우도 있습니다.

IIS의 애플리케이션 풀은 기본적으로 사용자 프로필을 로드하지 않고 동작합니다. loadUserProfile을 활성화하면 프로필 하위의 AppData나 하이브를 쓸 수 있게 됩니다.7 이 설정은 다음 장의 DPAPI나 ASP.NET Core Data Protection의 키 저장 위치와도 관계됩니다.

작업의 「암호를 저장하지 않음」 설정은 이것과는 별개로 로그온 유형의 제약으로서 확인합니다. 같은 사용자를 지정하고 있어도 S4U 로그온에서는 네트워크나 EFS를 쓸 수 없습니다. 구체적인 구성의 차이는 8장에 정리합니다.6

5. 경계 3: DPAPI ── 암호는 「사용자의 키」로 걸려 있다

AppData와 HKCU가 「찾는 곳이 다르다」는 문제인 데 비해, DPAPI에서는 파일을 읽을 수 있어도 내용을 복호화할 수 없다는 문제가 일어납니다. 저장된 비밀번호를 쓰는 앱의 서비스화에서 CryptographicException이 되는 예가 이것입니다.

5.1 마스터 키의 주인이 다르면 복호화할 수 없다

DPAPI (Data Protection API)는 Windows가 앱에 제공하는 암호화 기능입니다. CryptProtectData나 .NET의 ProtectedData.Protect를 호출하면 앱 자신이 암호 키를 코드로 들고 다니지 않고도 데이터를 보호할 수 있습니다.13

다만 키가 불필요해지는 것은 아닙니다. OS가 관리하는 마스터 키를 사용합니다. CurrentUser 스코프에서는 무작위로 생성한 사용자별 마스터 키를 로그온 자격 증명에서 파생한 키로 보호하고 프로필 하위에 저장합니다.14

DPAPI의 키 연쇄무작위로 생성된 사용자의 마스터 키는 로그온 자격 증명에서 파생한 키로 보호되고, 그 마스터 키가 앱의 비밀을 암호화하고 있으며, 다른 사용자의 마스터 키로는 같은 암호문을 복호화할 수 없다파생 키로 보호암호화복호화할 수 없다로그온 자격 증명여러분의 마스터 키앱의 비밀 (저장된 비밀번호 등)다른 사용자의 마스터 키저장 위치는 프로필 하위

그림 6: 자격 증명으로 직접 데이터를 암호화하는 것이 아니라, 자격 증명에서 유래한 키로 마스터 키를 보호합니다.

다음은 사용자 A가 암호화한 데이터를 공유 위치에 두고 다른 사용자로 복호화를 시도하는 최소 예입니다. 저장 위치를 공유해도 CurrentUser의 복호화 주체는 달라지지 않습니다.

# 사용자 A의 세션에서: CurrentUser 스코프로 암호화해 공유 위치에 저장
Add-Type -AssemblyName System.Security
$bytes = [Text.Encoding]::UTF8.GetBytes("secret")
$enc = [Security.Cryptography.ProtectedData]::Protect($bytes, $null, "CurrentUser")
[Convert]::ToBase64String($enc) | Set-Content C:\ProgramData\demo.bin

# 다른 사용자로 (예를 들어 PsExec으로 SYSTEM이 되어) 복호화를 시도한다
$enc = [Convert]::FromBase64String((Get-Content C:\ProgramData\demo.bin))
[Security.Cryptography.ProtectedData]::Unprotect($enc, $null, "CurrentUser")
# → CryptographicException: 현재 상태에서는 유효하지 않은 데이터입니다

5.2 스코프는 복호화할 수 있어야 하는 상대로부터 고른다

스코프 복호화의 단위 설계상의 주의점
CurrentUser 암호화한 사용자의 마스터 키 다른 실행 계정으로 옮기면 복호화할 수 없다
LocalMachine 같은 머신의 공통 키 같은 머신 위의 임의의 프로세스에서 복호화할 수 있으므로, 암호문을 읽을 수 있는 상대를 파일 ACL로 좁힌다

서비스와 대화형 사용자 양쪽이 읽는 비밀은 처음부터 LocalMachine과 파일 ACL을 조합해 설계하거나, 암호화한 본인의 계정으로 실행합니다. 단지 복호화 오류를 없애기 위해 스코프를 바꾸는 것이 아니라, 누구에게 복호화를 허용할지를 정합니다.공용 단말에서는 머신 단위의 보호가 지나치게 넓다는 위험에도 주의하십시오.15

DPAPI 스코프를 고르는 법복호화할 수 있어야 하는 주체가 그 사용자뿐이면 CurrentUser 스코프를, 같은 PC의 여러 실행 주체라면 LocalMachine 스코프를 고르고 후자는 파일 ACL로 독자를 좁힌다그 사용자만같은 PC의 여러 실행 주체누가 복호화할 수 있어야 하는가CurrentUser 스코프LocalMachine 스코프다른 사용자 실행에서 복호화 실패독자는 파일 ACL로 좁힌다

그림 7: 스코프는 「어쩌다 동작한 쪽」이 아니라 복호화 주체의 설계로서 고릅니다.

5.3 비밀번호의 「변경」과 「재설정」은 다르다

마스터 키를 지키는 키는 로그온 자격 증명에 의존합니다. 사용자 자신이 비밀번호를 변경하면 마스터 키가 새 비밀번호에서 유래한 키로 다시 보호되어 복호화 능력을 이어받습니다.

한편 관리자가 로컬 계정의 비밀번호를 재설정하면 과거의 암호문을 복호화할 수 없게 되는 경우가 있습니다. 계정이 같더라도 자격 증명의 변경 방법까지 확인할 필요가 있습니다.14

5.4 ASP.NET Core에서도 키의 저장 위치를 확인한다

DPAPI를 직접 호출하지 않아도 이 경계에 의존하는 경우가 있습니다. ASP.NET Core Data Protection은 쿠키 인증 등의 보호에 쓰는 키 링을 환경에 따른 위치에 저장합니다.16

환경 키가 놓이는 곳과 영향
사용자 프로필을 쓸 수 있다 %LOCALAPPDATA%\ASP.NET\DataProtection-Keys. Windows에서는 DPAPI로 암호화한다
프로필을 쓸 수 없고 IIS에서 호스팅되고 있다 작업자 프로세스 계정에 ACL을 설정한 HKLM 레지스트리 하위로 폴백한다
어느 쪽에도 해당하지 않는다 프로세스 내에 한정된 임시 키가 된다. 재시작으로 키를 잃어 인증 쿠키 등의 보호된 데이터가 무효가 된다

loadUserProfile, setProfileEnvironment, 호스팅 형태를 한 묶음으로 확인해 키가 어디에 놓이는 구성인지를 파악합니다. 「시작할 수 있다」뿐 아니라 재시작 후에도 같은 키를 쓸 수 있는지가 중요합니다.

스코프 선택과 Credential Manager의 구분은 「Windows 앱의 기밀 정보 저장 - DPAPI로 평문 설정을 피하기」에서 자세히 다루고 있습니다.

6. 경계 4: 브라우저 프로필 ── 「로그인 완료」는 사용자의 소유물

내 PC에서는 로그인되어 있는데 CI에서 브라우저를 시작하면 로그인 화면으로 돌아간다.이 문제는 프로필의 저장 위치와 암호 키를 나누면 정리할 수 있습니다.

6.1 저장 위치와 키라는 두 개의 경계가 있다

Chrome이나 Edge 같은 Chromium 계열 브라우저의 프로필은 기본적으로 %LOCALAPPDATA% 하위의 User Data 폴더에 있습니다. 방문 기록·쿠키·확장·저장된 비밀번호 등은 그 Windows 사용자의 환경에 속합니다.17

쿠키나 저장된 비밀번호는 프로필 안의 암호 키로 암호화되고, 그 키 자체가 DPAPI로 보호되어 있습니다. 따라서 다른 사용자나 다른 머신으로 폴더를 복사해도 키가 맞지 않아 복호화할 수 없습니다.

최근의 Chrome은 App-Bound Encryption (앱 결속 암호화)도 겹쳐 놓고 있습니다. 키의 복호화를 SYSTEM 권한의 서비스를 거치게 하고, 사용자뿐 아니라 요청한 앱의 ID까지 검증합니다.18 이것은 Chromium 계열의 이야기이며, 독자적인 프로필 보호를 갖춘 Firefox 등에서는 사정이 다릅니다.

경계 자동화 대상에서 일어나는 일
AppData의 경계 CI 에이전트나 서비스의 사용자에게는 평소 쓰는 프로필이 없다
DPAPI의 경계 폴더를 복사해도 보호된 키를 복호화할 수 없다
브라우저의 로그인 상태를 떠받치는 2개의 경계브라우저 프로필은 LOCALAPPDATA 하위에 있어 경계 1에 속하고, 쿠키의 암호 키는 DPAPI로 보호되어 경계 3에 속하므로, 다른 사용자에게는 프로필도 키도 이어지지 않는다브라우저 프로필놓이는 곳은 LOCALAPPDATA 하위쿠키 암호 키는 DPAPI로 보호CI의 실행 사용자에게는 비어 있는 다른 프로필폴더 복사로는 가져갈 수 없다

그림 8: 「로그인 완료를 가져간다」는 경계 1과 경계 3 양쪽에 막힙니다.

6.2 자동화에서는 로그인 상태를 만드는 방법을 명시한다

Selenium이나 Playwright는 기본적으로 일회용 임시 프로필을 만들어 시작합니다. 그래서 같은 사용자라도 평소 브라우저의 로그인 상태가 자동으로 쓰이는 것은 아닙니다.

영속 프로필의 디렉터리를 지정해도 다른 사용자의 CI나 서비스로 옮기는 단계에서는 앞 절의 저장 위치와 키의 문제가 남습니다. 대책은 로그인된 프로필을 복사하는 것이 아니라 다음 둘 중 하나입니다.

  • 테스트용 계정의 로그인 절차를 코드로 만든다.
  • 자동화 도구의 스토리지 스테이트 기능으로 쿠키 등의 저장·복원을 명시한다.

다른 사용자가 복사만으로 쿠키를 쓸 수 없다는 것은 불편함이 아니라 보안상의 경계이기도 합니다. 자동화의 설계는 그 경계가 있다는 것을 전제로 합니다.

7. 경계 5: 자격 증명과 인증서 ── 금고는 사용자마다 따로

cmdkey로 저장한 자격 증명이 작업 실행 시에는 쓰이지 않아 인증 오류가 난다.여기서도 「PC에 저장했다」가 아니라 「어느 사용자로서 저장했는가」를 확인합니다.

7.1 자격 증명 관리자는 실행 사용자별 금고

cmdkey /list로 확인할 수 있는 자격 증명 관리자는 사용자별 금고입니다.19 저장한 자격 증명은 디스크 위에 있지만 DPAPI로 보호되어 있고, 그 사용자로서 동작하는 프로그램이 사용합니다.20

금고에는 파일 서버나 네트워크 드라이브의 저장 자격 증명, git-credential-manager가 저장한 Git 토큰, RDP 연결의 저장 비밀번호, Credential API를 쓰는 앱의 시크릿 등이 들어갑니다.

대화형 로그온한 자신의 금고에 있어도 서비스나 작업의 실행 계정의 금고에는 없습니다. 필요한 자격 증명은 실행 계정 자신의 컨텍스트에서 넣는 셋업을 준비합니다. 손안의 git pull만 성공하는 경우에도 쓰고 있는 금고의 차이를 확인합니다.

다만 S4U 구성의 작업은 자격 증명을 넣는 것만으로는 해결되지 않습니다. 먼저 로그온 유형을 확인하고, 암호를 저장하는 구성이나 서비스 계정으로의 전환을 검토합니다. 절차의 순서는 8장에서 정리합니다.

자격 증명의 금고는 사용자마다여러분의 금고에는 git의 자격 증명이나 파일 서버의 저장 자격 증명이나 RDP의 비밀번호가 들어 있지만, 서비스 실행 사용자의 금고는 자격 증명을 넣지 않는 한 비어 있으며 그것이 인증 오류의 정체가 된다여러분의 금고git의 자격 증명파일 서버의 저장 자격 증명RDP의 저장 비밀번호서비스 실행 사용자의 금고넣지 않았으면 비어 있음 = 인증 오류의 정체

그림 9: 「내 PC에서는 인증이 통과한다」는 「여러분의 금고를 쓸 수 있다」의 줄임말일 뿐입니다.

7.2 인증서는 저장소와 개인 키의 권한을 나누어 확인한다

저장소 경계와 용도
Cert:\CurrentUser 사용자별 저장소. 여기에 넣은 클라이언트 인증서의 개인 키는 사용자 단위로 보호된다
Cert:\LocalMachine 머신 전체의 저장소. 서비스용 인증서를 넣고 개인 키의 ACL로 서비스 계정에 읽기를 허용한다

서비스에서 쓰는 인증서는 LocalMachine 저장소와 개인 키의 ACL을 한 묶음으로 설계하는 것이 기본입니다.21 사용자 저장소의 실체는 HKCU\Software\Microsoft\SystemCertificates 하위이므로 HKCU 경계의 안쪽에 있습니다.22

자세한 내용은 「Windows 인증서 저장소 실무 가이드 ── 사용자와 컴퓨터, 어느 쪽에 넣을 것인가」를 참조하십시오.

7.3 UAC 권한 상승에서는 「같은 계정」과 「다른 계정」을 나눈다

UAC가 활성화된 관리자 사용자의 로그온에서는 권한을 제한한 표준 토큰과 완전한 관리자 토큰이라는 연결된 두 개의 토큰이 만들어집니다.8

네트워크 드라이브의 할당은 로그온 세션 단위입니다. 탐색기에서는 Z:가 보여도 관리자로 실행한 도구에서는 보이지 않는 경우가 있습니다.9

실행 방법 달라지는 것·달라지지 않는 것
같은 계정인 채로 UAC 권한 상승한다 SID는 같고 HKCU나 자격 증명 금고도 그대로. 로그온 세션 단위의 드라이브 할당이 보이지 않게 되는 경우가 있다
다른 관리자 계정의 자격 증명으로 권한 상승한다 / RunAs 한다 SID도 달라진다. HKCU나 금고는 그 관리자의 것이 된다. AppData·키·브라우저 상태도 다른 사용자의 경계를 받는다

「권한 상승했더니 동작하지 않는다」를 전부 사용자의 변경이라고 단정하지 말고, 먼저 같은 계정인지를 확인합니다.

UAC 권한 상승이 낳는 같은 사용자 안의 분열UAC가 활성화된 관리자의 로그온은 표준 토큰과 상승 토큰의 2개를 만들며, 표준 토큰 쪽에서 할당한 네트워크 드라이브가 상승 토큰의 프로세스에서는 보이지 않는다다른 로그온 세션관리자 사용자의 로그온표준 토큰상승 토큰여기서 할당한 Z: 드라이브권한 상승한 도구에서 Z:가 보이지 않는다

그림 10: 권한 상승은 「같은 사용자의 다른 세계」를 만듭니다. 경계는 SID만의 이야기가 아닙니다.

8. 실행 형태별 체크리스트

8.1 작업에서는 실행 계정 다음으로 로그온 유형을 본다

작업 스케줄러는 같은 사용자를 지정해도 로그온 유형에 따라 이용할 수 있는 것이 달라집니다.6

로그온 유형 확인할 것
대화형 토큰 (InteractiveToken) 로그온 중인 세션에서 실행하는 구성
암호 저장 (Password) 비대화형에서도 자격 증명을 쓸 수 있는 구성
S4U (암호 비저장) 암호를 저장하지 않으며 네트워크 리소스와 암호화 파일 (EFS)에 액세스할 수 없다

저장 자격 증명을 쓸 수 없는 작업은 먼저 S4U의 제약을 확인합니다. S4U인 채로 금고에 자격 증명을 더하는 것을 대책으로 삼지 마십시오.암호를 저장하는 구성이나 서비스 계정으로의 전환을 검토하고, 그 위에서 필요하다면 실행 계정의 금고에 넣습니다.

설정의 자세한 내용은 「작업 스케줄러 작업이 실행되지 않거나 0x1로 끝나는 경우 ── 원인 분리와 안전한 운영 설계」에서 다루고 있습니다.

작업의 로그온 유형이라는 제2의 축작업 스케줄러의 실행 구성은 대화형 토큰, 암호 저장, S4U라는 로그온 유형을 가지며 S4U에서는 암호가 저장되지 않고 네트워크와 EFS에 액세스할 수 없다대화형 토큰암호 저장S4U (암호 비저장)작업의 실행 구성로그온 유형로그온 중인 세션에서 실행비대화형에서도 자격 증명을 쓸 수 있다네트워크와 EFS에 닿지 않는다

그림 11: 같은 실행 사용자라도 로그온되는 방식에 따라 쓸 수 있는 것이 달라집니다.

8.2 실행 대상을 바꾸기 전의 점검표

실행 형태 실행 주체 특히 점검할 경계와 증상
작업 스케줄러 등록 시에 지정한 계정 경계 1·2·3·5. AppData나 HKCU의 참조 대상, DPAPI의 복호화, 금고를 확인한다. S4U에서는 네트워크·EFS를 쓸 수 없다
Windows 서비스 SYSTEM, LocalService, NetworkService, 서비스 계정 경계 1~5. SYSTEM은 systemprofile과 기본 사용자의 HKCU를, LocalService/NetworkService는 ServiceProfiles 하위의 각 환경을 쓴다. 개발자의 키·금고·브라우저 상태는 이어지지 않는다
IIS 앱 풀 IIS AppPool\<이름> 등의 풀 고유 ID 경계 1·2·3·5. 기본적으로 프로필 미로드, Data Protection의 키 저장 위치, CurrentUser 인증서의 개인 키에 대한 액세스를 확인한다
RunAs/UAC 권한 상승 지정한 사용자, 또는 같은 사용자의 다른 토큰 같은 계정이면 SID·HKCU·금고는 같고 드라이브 할당은 세션의 차이를 받는다. 다른 계정이면 경계 1~5 전부를 점검한다
CI/CD 에이전트 에이전트의 서비스 사용자. 대화형 로그온 이력이 없는 경우도 많다 경계 1~5. 브라우저의 프로필·로그인 상태, Git의 자격 증명, 개발자의 HKCU 설정이나 DPAPI 보호 데이터에 의존하고 있지 않은지 확인한다
RDP/공용 서버 같은 사용자의 다중 세션, 또는 여러 사용자 같은 사용자의 다중 세션은 AppData·HKCU를 공유하므로 쓰기 경합에 주의한다. 다른 사용자면 경계 1~5에서 갈린다

마지막 행은 반대 방향의 주의입니다. 같은 사용자의 RDP 세션이 여러 개 있어도 AppData나 HKCU가 세션마다 독립되는 것은 아닙니다.여기서는 「보이지 않는다」가 아니라 「같은 것을 공유해 쓴다」가 문제가 됩니다.

9. 설계와 문제 해결의 지침

9.1 저장 위치와 셋업을 이용하는 주체로부터 정한다

대상 설계의 기본
사용자 고유의 설정 AppData·HKCU에 둔다
모든 사용자나 서비스가 공유하는 데이터·설정 ProgramData·HKLM에 두고 쓰기 권한과 ACL을 설계한다
비밀 정보 DPAPI의 스코프를 복호화할 수 있어야 하는 상대로부터 고른다. LocalMachine에서는 파일 ACL도 설계한다
서비스용 자격 증명·인증서 실행 계정의 금고에 넣기, LocalMachine 인증서 저장소에 배치하기와 개인 키의 ACL 설정을 셋업 절차에 포함한다

장래에 서비스화할 예정이 있다면 저장 위치를 정하는 단계에서 그 실행 주체도 독자에 포함합니다. 「어쩌다 개발자의 환경에 있던 것을 쓴다」는 의존을 운영으로 가져가지 않는 것이 원칙입니다.

9.2 조사는 실행 주체에서 실제 참조 대상으로 나아간다

사용자 경계 문제의 조사 절차whoami로 실행 사용자를 확인하고, Process Explorer로 토큰을 보고, Process Monitor로 실제로 읽은 경로와 레지스트리 키를 특정하고, 필요하면 psexec으로 상대의 세계에서 재현한다whoami /all로 실행 사용자를 확인Process Explorer로 토큰을 확인ProcMon으로 실제 경로와 키를 특정psexec으로 상대의 세계에서 재현예상과 다른 프로필 경로가 단서

그림 12: 실행 사용자를 확인하고 실제 경로와 레지스트리 키를 본 다음, 대상 실행 주체에서 재현합니다.

절차 확인 방법 볼 지점
1. 실행 사용자를 확인한다 시작 직후에 whoami /all을 로그로 출력한다 문제가 일어나는 작업이나 서비스의 실행 주체가 내 PC와 같은지
2. 토큰을 확인한다 Process Explorer 프로세스의 사용자와 세션. 다른 사용자인지, 같은 사용자의 다른 실행 컨텍스트인지
3. 실제 참조 대상을 본다 Process Monitor 연 파일의 경로와 레지스트리 키. PATH NOT FOUND에 예상과 다른 프로필이 나타나 있지 않은지
4. 대상 실행 주체에서 재현한다 SYSTEM이면 psexec -s -i cmd SYSTEM의 셸에서 같은 조작을 시도해 자신의 대화형 환경과의 차이를 확인한다

설정이 없을 때는 AppData와 HKCU, 파일은 읽히는데 복호화할 수 없을 때는 DPAPI, 인증만 실패할 때는 금고·인증서·로그온 유형으로 돌아갑니다. 오류 메시지만으로 판단하지 말고 「누가, 어디를, 어느 키나 자격 증명으로 썼는가」를 맞추는 것이 지름길입니다.

10. 정리

「내 PC에서 동작한다」는 「그 사용자, 그 프로필, 그 키와 금고에서 동작한다」는 의미입니다.같은 PC에서 같은 .exe를 시작해도 작업화·서비스화·CI화는 실행 환경의 이전으로 다룰 필요가 있습니다.

AppData와 사용자 환경 변수는 실행 사용자의 프로필을 참조하고, HKCU도 그 사용자의 하이브를 향합니다. DPAPI의 CurrentUser 스코프는 사용자의 마스터 키에 의존하며, 브라우저의 로그인 상태와 자격 증명 관리자도 그 경계의 영향을 받습니다.

나아가 같은 SID라도 로그온 유형, 프로필 로드, UAC 권한 상승에 따른 세션의 차이가 남습니다. 반대로 같은 사용자의 여러 세션이 AppData나 HKCU를 공유하는 경우에는 쓰기 경합을 생각합니다.

설계 리뷰에서는 다음 물음을 확인하십시오.

이것은 어느 사용자로 동작해도 올바른 코드인가?

필요한 저장 위치·키·자격 증명을 실제 실행 주체에 명시적으로 준비한다. 이 원칙을 이전 전에 확인하면 「코드는 바꾸지 않았는데 망가졌다」는 사고를 설계 단계에서 줄일 수 있습니다.

관련 기사

관련 상담 영역

합동회사 코무라소프트에서는 업무 앱의 서비스화·작업화에 따른 실행 환경의 설계, 「내 PC에서는 동작하는데」형 결함 조사, Windows 앱의 비밀 정보 관리 설계를 다루고 있습니다.

참고 링크

  1. Microsoft Learn, About User Profiles. 사용자 프로필이 첫 로그온 시에 만들어진다는 점, 프로필이 레지스트리 하이브 NTUSER.DAT (로그온 시에 로드되어 HKEY_CURRENT_USER에 매핑된다)와 파일 시스템상의 프로필 폴더들로 이루어진다는 점에 대해.  2

  2. Microsoft Learn, Local accounts. SYSTEM (S-1-5-18), NETWORK SERVICE (S-1-5-20), LOCAL SERVICE (S-1-5-19)가 OS와 서비스의 실행에 쓰이는 기본 로컬 시스템 계정이라는 점에 대해. 

  3. Microsoft Learn, LocalSystem Account. LocalSystem의 토큰이 NT AUTHORITY\SYSTEM을 포함한다는 점, 어떤 로그온 사용자 계정과도 연결되지 않는다는 점, 그래서 HKEY_CURRENT_USER가 기본 사용자에 연결되며 다른 사용자의 프로필에 액세스하려면 그 사용자를 가장해야 한다는 점에 대해.  2

  4. Microsoft Learn, LocalService Account. LocalService 계정이 HKEY_USERS 아래에 자신의 하위 키를 가진다는 점, HKEY_CURRENT_USER가 LocalService 계정에 연결된다는 점에 대해. NetworkService도 마찬가지 (NetworkService Account).  2

  5. Microsoft Learn, Application Pool Identities. 애플리케이션 풀이 풀 고유의 ID로 동작한다는 점, IIS가 기본적으로 Windows 사용자 프로필을 로드하지 않는다는 점, LoadUserProfile 특성을 true로 하면 프로필을 로드할 수 있다는 점에 대해. 

  6. Microsoft Learn, logonType Simple Type. 작업의 로그온 유형에 S4U, Password, InteractiveToken이 있다는 점, S4U 로그온에서는 암호가 저장되지 않으며 네트워크에도 암호화 파일에도 액세스할 수 없다는 점에 대해.  2 3

  7. Microsoft Learn, Process Model Settings for an Application Pool. 애플리케이션 풀의 processModel에 loadUserProfile 특성과 setProfileEnvironment 특성이 있어 작업자 프로세스가 사용자 프로필을 로드할지를 제어한다는 점에 대해.  2

  8. Microsoft Learn, How User Account Control works. UAC 활성화 시, 관리자 사용자의 로그온에서 표준 사용자 토큰과 완전한 관리자 액세스 토큰이라는 2개의 연결된 토큰이 만들어진다는 점에 대해.  2

  9. Microsoft Learn, Mapped drives are not available from an elevated prompt. 표준 토큰으로 로그온한 세션에서 할당한 네트워크 드라이브를 권한 상승한 프로세스에서 이용할 수 없다는 점, 그 배경으로 연결된 2개의 로그온 세션이 각각 드라이브 할당을 가진다는 점에 대해.  2

  10. Microsoft Learn, KNOWNFOLDERID. FOLDERID_RoamingAppData (%APPDATA%), FOLDERID_LocalAppData (%LOCALAPPDATA%), FOLDERID_LocalAppDataLow가 사용자별 알려진 폴더로 정의되어 있다는 점에 대해. 

  11. Microsoft Learn, Error occurs during desktop setup and desktop location is unavailable. 사용자 프로필이 NTUSER.DAT와 UsrClass.dat라는 2개의 하이브 파일을 가진다는 점, UsrClass.dat이 AppData\Local\Microsoft\Windows 하위에 놓인다는 점에 대해. 

  12. Microsoft Learn, Services and the Registry. 서비스가 HKEY_CURRENT_USER나 HKEY_CLASSES_ROOT에 액세스해서는 안 된다는 점, 사용자를 가장하는 경우에는 RegOpenCurrentUser 함수를 써야 한다는 점에 대해. 

  13. Microsoft Learn, CryptProtectData function. CryptProtectData가 보통 로그온한 사용자에 연결된 세션 키로 데이터를 보호하고 같은 사용자에서의 복호화를 전제로 한다는 점, CRYPTPROTECT_LOCAL_MACHINE 플래그로 머신 단위의 보호로 전환할 수 있다는 점에 대해. 

  14. Microsoft Learn, Windows Data Protection. DPAPI가 무작위로 생성한 마스터 키를 사용자의 암호에서 파생한 키로 암호화해 보호한다는 점, 마스터 키가 사용자 프로필 하위에 저장된다는 점, 암호 변경 시에 마스터 키가 다시 보호된다는 점에 대해.  2

  15. Microsoft Learn, ProtectedData Class. DataProtectionScope.CurrentUser가 보호한 사용자에게만 복호화를 허용하고, LocalMachine이 같은 머신 위의 임의의 프로세스로부터의 복호화를 허용한다는 점에 대해. 

  16. Microsoft Learn, Data Protection key management and lifetime in ASP.NET Core. 사용자 프로필을 이용할 수 있는 경우 키가 %LOCALAPPDATA%\ASP.NET\DataProtection-Keys에 저장되고 Windows에서는 DPAPI로 암호화된다는 점, IIS 호스트에서 프로필을 쓸 수 없는 경우에는 작업자 프로세스 계정에 ACL이 설정된 HKLM 레지스트리로 폴백한다는 점, 어느 조건에도 해당하지 않는 경우 키가 프로세스 종료와 함께 사라져 보호된 페이로드를 복호화할 수 없게 된다는 점, setProfileEnvironment 특성이 관계된다는 점에 대해. 

  17. Chromium project, User Data Directory. Windows에서 Chrome의 User Data 디렉터리의 기본값이 %LOCALAPPDATA%\Google\Chrome\User Data이며, 프로필 (방문 기록, 북마크, 쿠키 등)이 그 하위에 놓인다는 점에 대해. 

  18. Google Security Blog, Improving the security of Chrome cookies on Windows. Chrome이 Windows에서 쿠키 등의 암호화에 DPAPI를 써 왔다는 점, App-Bound Encryption으로 키를 SYSTEM 권한의 서비스를 거쳐 보호하고 복호화를 요구한 앱의 ID까지 검증하게 되었다는 점에 대해. 

  19. Microsoft Learn, cmdkey. cmdkey 명령으로 저장된 사용자 이름과 암호 (자격 증명)의 목록 표시, 생성, 삭제를 할 수 있다는 점에 대해. 

  20. Microsoft Learn, Cached and Stored Credentials Technical Overview. 자격 증명 관리자에 저장된 자격 증명이 디스크 위에 놓이고 DPAPI로 보호된다는 점, 그 사용자로서 동작하는 프로그램이 이 저장소의 자격 증명에 액세스할 수 있다는 점에 대해. 

  21. Microsoft Learn, Local Machine and Current User Certificate Stores. 인증서 저장소에 로컬 머신 저장소 (머신 전체)와 현재 사용자 저장소 (사용자별)의 2종류가 있다는 점에 대해. 

  22. Microsoft Learn, System Store Locations. CERT_SYSTEM_STORE_CURRENT_USER의 시스템 저장소가 레지스트리의 HKEY_CURRENT_USER\Software\Microsoft\SystemCertificates 하위에 놓인다는 점에 대해. 

같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.

이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.

이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.

자주 묻는 질문

이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.

탐색기에서 실행하면 동작하는 앱이 작업 스케줄러에서는 설정 파일을 찾지 못합니다. 왜 그런가요?
%APPDATA% 같은 환경 변수가 「실행하고 있는 사용자」의 프로필로 해석되기 때문입니다. 작업을 SYSTEM이나 다른 계정으로 실행하면 환경 변수는 다른 프로필 (SYSTEM이면 systemprofile 하위)을 가리키고, 여러분이 저장한 설정 파일은 거기에 존재하지 않습니다. 작업의 실행 계정을 확인하고, 공유해야 할 데이터는 ProgramData 하위에 두는 것이 항구적인 대책입니다.
ProtectedData.Protect로 저장한 비밀번호가 서비스로 만든 뒤에는 복호화되지 않습니다.
CurrentUser 스코프의 DPAPI는 암호화한 사용자의 마스터 키에 의존합니다. 서비스의 실행 계정이 다르면 마스터 키도 다른 것이므로 복호화는 CryptographicException으로 실패합니다. 서비스와 대화형 사용자 양쪽에서 읽는 비밀은 LocalMachine 스코프와 파일 ACL로 다시 설계하거나, 암호화한 본인의 계정으로 서비스를 실행하십시오.
SYSTEM으로 동작하는 프로세스에서 HKCU를 읽으면 어떻게 되나요?
LocalSystem 프로세스에서는 HKEY_CURRENT_USER가 기본 사용자 (HKEY_USERS\.DEFAULT)에 연결되므로, 대화형 사용자가 HKCU에 쓴 값은 보이지 않습니다. 머신 전체에서 공유하는 설정은 HKLM에 두고, 꼭 사용자의 설정을 읽어야 한다면 그 사용자를 가장한 뒤에 RegOpenCurrentUser를 사용하십시오.
로그인된 Chrome/Edge 프로필을 CI 머신에 복사해서 쓸 수 있나요?
기본적으로 쓸 수 없습니다. Chrome이나 Edge 같은 Chromium 계열 브라우저의 프로필은 그 사용자의 %LOCALAPPDATA% 하위에 있고, 쿠키와 저장된 비밀번호의 암호 키는 그 사용자의 DPAPI로 보호됩니다. 다른 사용자나 다른 머신으로 폴더를 복사해도 키가 맞지 않아 복호화할 수 없습니다 (Firefox처럼 독자적인 프로필 보호를 갖춘 브라우저는 사정이 다릅니다). 자동화에서는 테스트용 계정의 로그인 절차를 코드로 만들거나, 자동화 도구의 스토리지 스테이트 기능을 사용하십시오.
cmdkey로 저장한 자격 증명이 작업 스케줄러 실행 시에는 사용되지 않습니다.
자격 증명 관리자의 금고는 사용자마다 따로이고, 저장한 것은 대화형 로그온한 여러분 자신의 금고이기 때문입니다. 게다가 「암호를 저장하지 않음」 (S4U) 구성의 작업은 네트워크 자격 증명 없이 동작하므로, S4U인 채로는 금고에 자격 증명을 넣어도 쓸 수 없습니다. 먼저 「암호를 저장함」 구성이나 서비스 계정으로의 전환을 검토하고, 그 위에서 필요하다면 실행 계정 자신의 금고에 자격 증명을 넣으십시오.

저자 프로필

기사 저자의 프로필 페이지입니다.

Go Komura

합동회사 코무라소프트 대표

Windows 소프트웨어 개발, 기술 상담, 장애 조사를 중심으로 재현이 어려운 장애 조사와 기존 자산이 남아 있는 프로젝트에 강점이 있습니다.

블로그 목록으로 돌아가기