AI에게 비밀번호를 노출하지 않는 방법: 브라우저 자동화를 위한 로컬 자격 증명 브로커 설계
요약
AI 에이전트가 로그인 과정에서 비밀번호를 직접 노출하는 위험성을 해결하기 위해, 로컬 자격 증명 브로커 설계 방안을 제시합니다. 이 방식은 AI에게 값(value) 자체를 전달하지 않고, '어디에 채워야 하는지'만 지시하여 보안을 강화합니다.
핵심 포인트
- 비밀번호는 OS 사용자 단위 암호화(DPAPI 등)로 보관해야 합니다.
- AI가 평문 비밀번호를 반환하는 API를 만들지 않아 노출 경로를 차단합니다.
- 입력 대상 검증은 origin뿐 아니라 경로(path prefix)까지 세밀하게 해야 합니다.
- CAPTCHA나 MFA는 브로커가 직접 처리하지 않고 사람에게 요청해야 합니다.
AI 에이전트에게 브라우저 조작을 맡기면, 반드시 로그인 화면에 부딪히게 됩니다. 여기서 가장 피해야 할 것은 'AI에게 비밀번호를 넘겨주는 것'입니다. 프롬프트에 작성하거나 메모리에 기억하게 해도, 대화 로그, 전송처, 학습 시스템 등 어디로 유출될지 통제할 수 없습니다.
저는 'AI는 값(value)을 보지 않고, 채워야 할 위치만 지시하는' 구조로 결정했습니다. 로컬에 자격 증명 브로커를 두고, AI가 브로커에게 '이 사이트의 이 칸을 채워줘'라고 요청하기만 하는 방식입니다. 본 글은 그 설계에 대한 내용입니다.
전체 개요
원칙은 세 가지입니다.
- 평문(Plaintext)을 저장하지 않는다: OS 사용자 단위 암호화 (Windows의 경우 DPAPI)로 보관합니다.
- AI에게 평문을 반환하는 API를 만들지 않는다: 브로커가 화면에 직접 입력합니다. 읽어낼 수 있는 출구(출력 경로)를 두지 않아 노출 경로를 줄입니다.
- 입력 대상을 엄격하게 검증한다: 등록할 때 정한 장소 외에는 절대 입력하지 않습니다.
저장: DPAPI로 사용자 단위 암호화
Windows의 경우 추가 소프트웨어 없이 OS 보호 API를 사용할 수 있습니다. 실제 코드를 보여드립니다.
function Protect-Text([string]$PlainText, [byte[]]$Entropy) {
$bytes = [Text.Encoding]::UTF8.GetBytes($PlainText)
try {
...
}
CurrentUser 스코프를 사용하면 암호화된 데이터를 같은 Windows 사용자에게 묶을 수 있습니다. 다른 사용자에게 파일만 넘겨도 복호화할 수 없습니다. 다만, 같은 사용자 권한으로 실행되는 악성코드나 침해된 프로세스까지 막아주는 구조는 아닙니다. 이것은 비밀 관리의 만능 해결책이 아니라, 평문 파일을 두는 것보다 노출을 줄이기 위한 한 단계일 뿐입니다.
finally 블록에서 UTF-8로 변환한 바이트 배열은 삭제하지만, 인수의 .NET 문자열은 불변(immutable)이므로 완전한 삭제를 보장할 수는 없습니다. 더 엄격하게 처리하려면, 등록 UI부터 보호 처리까지 평문의 수명을 짧게 하고 로그, 예외, 커맨드라인에 노출되지 않도록 설계하는 것도 필요합니다. DPAPI의 동작 방식은 Microsoft Learn의 ProtectedData 설명을 통해 확인할 수 있습니다.
입력 대상 검증: origin만으로는 부족했다
'등록한 사이트에만 입력한다'는 검증을 처음에는 origin(스키마+호스트) 일치로 만들었습니다.
export function normalizeAllowedOrigin(value) {
const url = new URL(value)
if (url.pathname !== '/' || url.search || url.hash || url.username || url.password) {
...
}
그런데 실제 채용 포털 중에는 하나의 호스트에 여러 기업의 로그인 화면이 공존하는 경우가 있습니다. origin 일치만으로는 A사 전용 ID/비밀번호를 B사 로그인 화면에 입력할 수 있게 됩니다. 그래서 적용 범위를 경로(path) 접두어까지 좁혔습니다.
/** 대상 URL이 허용된 접두어 아래에 있는지 확인합니다.
접두어가 설정되지 않은 경우(전용 호스트)는 origin 일치만으로 판별합니다 */
export function urlWithinAllowedScope(rawUrl, allowedOrigin, allowedPathPrefix) {
...
}
교훈: '어디에 입력해도 되는가'의 세밀함은 호스트가 아니라 테넌트입니다. 공유 호스트 형태의 서비스를 다룬다면 처음부터 경로까지 확인해야 합니다.
입력하지 않는 용기: CAPTCHA와 MFA는 즉시 중단
로그인 화면을 읽었을 때, CAPTCHA나 일회용 코드 입력을 감지하면 브로커는 아무것도 하지 않고 '사람에게 요청'을 반환합니다.
if (document.querySelector('.g-recaptcha, [data-sitekey]') ||
/captcha|ロボットではない/i.test(bodyText)) blockers.push('captcha')
if (document.querySelector('input[autocomplete=
작업 | 담당
|---|---|
| 로그인 화면까지의 이동 및 필드 특정 | AI 에이전트 |
| ... |
금융 관련 값은 '암호화하면 된다'가 아니라, **이 시스템의 방어 범위 외**로 규정합니다. 자동화의 가치는 로그인 빈도가 높은 정형 작업만으로 충분하므로, 위험도가 높은 값까지 욕심낼 필요는 없습니다.
## 요약
- AI에게 평문 비밀번호를 넘겨주지 않는다. 읽기 전용 API를 만들지 않고, 노출 경로를 줄인다.
- DPAPI는 Windows 사용자에게 연결되는 보호 계층이다. 침해된 동일 사용자까지는 막을 수 없다.
- 입력 대상의 검증은 origin + path prefix까지로 한다. 공유 호스트의 존재를 잊지 않는다.
- CAPTCHA, MFA(다단계 인증), 금융 정보는 처음부터 인간의 영역으로 명문화한다.
에이전트가 많아질수록, '손대지 못하게 할 장소'를 설계하는 것이 효과적입니다.
### 논의

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기