SON Kiseok Technical Blog

휴대폰에서 NAS 내부 브라우저의 로그인 세션을 안전하게 갱신한 방법

개인 채용시장 수집 자동화를 만들다 보면 공개 채용공고만 보는 것과 달리, 내 계정으로 로그인해야 확인할 수 있는 정보를 다뤄야 할 때가 있다.

이때 가장 단순한 방법은 계정 ID와 비밀번호를 자동화 코드에 넣는 것이다. 하지만 로그인 과정에 추가 인증이나 CAPTCHA가 생길 수 있고, 인증정보를 서버나 코드에 저장하는 것도 피하고 싶었다.

그래서 방향을 바꿨다.

로그인은 사람이 직접 하고, 자동화는 로그인 이후의 세션만 안전하게 재사용한다.

그리고 재인증이 필요할 때는 PC가 없어도 휴대폰 브라우저만으로 NAS 안의 브라우저에 접속할 수 있게 만들었다.

목적

이 구조의 목적은 단순히 “원격 브라우저를 띄우는 것”이 아니다.

개인 채용시장 수집 파이프라인에서 다음 조건을 동시에 만족하는 것이 목표였다.

  • 계정 ID와 비밀번호를 코드나 Git에 저장하지 않는다.
  • CAPTCHA나 추가 본인인증을 자동으로 우회하지 않는다.
  • 인증이 필요하면 사용자가 직접 처리한다.
  • 외부에서는 휴대폰 웹브라우저만 있으면 된다.
  • 평상시에는 NAS의 인증용 브라우저를 인터넷에 노출하지 않는다.
  • 인증이 끝나면 외부 접근 경로를 즉시 없앤다.
  • 브라우저의 로그인 상태만 NAS 로컬에 유지한다.
  • 다른 ChatGPT/Codex 세션에서도 같은 절차를 다시 사용할 수 있어야 한다.

즉, 편의성보다 인증정보를 자동화에 넣지 않는 구조와 재현 가능한 운영 절차를 우선했다.

처음 생각한 방법

초기에는 몇 가지 다른 접근을 검토했다.

1. PC 브라우저의 쿠키를 NAS로 복사

사용자가 PC에서 정상 로그인한 뒤 쿠키 파일을 NAS로 옮기면 비교적 단순하게 세션을 재사용할 수 있다.

하지만 이 방식은 매번 PC가 필요하고, 브라우저 쿠키 export 과정도 별도로 관리해야 한다.

제가 원한 것은 외부에서 휴대폰만 있을 때도 재인증할 수 있는 방식이었다.

2. NAS에서 ID와 비밀번호로 자동 로그인

자동화 관점에서는 가장 편해 보이지만 채택하지 않았다.

로그인 페이지 구조가 바뀌거나 추가 인증이 생기면 쉽게 깨지고, 무엇보다 계정 인증정보를 자동화 코드나 서버 설정에 보관해야 할 가능성이 커진다.

CAPTCHA나 MFA가 나타났을 때 이를 우회하는 방향으로 확장되는 것도 원하지 않았다.

3. 상시 원격 브라우저 공개

고정 도메인과 접근 제어를 두고 NAS 브라우저를 항상 원격에서 열 수 있게 하는 방법도 가능하다.

하지만 실제 사용 빈도는 “로그인 세션이 만료됐을 때 잠깐 재인증”하는 정도다.

항상 공개된 관리 화면을 운영할 이유가 없었다.

최종 구조

결국 다음 구조로 정리했다.

평상시
  외부 접근 경로 없음
  NAS 내부 Chromium profile만 유지

재인증이 필요할 때
  휴대폰 Chrome
    -> HTTPS 임시 Tunnel
    -> 긴 일회용 경로
    -> 임시 reverse proxy
    -> standard noVNC
    -> VNC
    -> 가상 디스플레이
    -> NAS 내부 Chromium
    -> 사용자가 직접 로그인

로그인 완료
  임시 Tunnel 제거
  임시 reverse proxy 제거
  일회용 URL 제거
  Chromium profile만 NAS 로컬에 유지

핵심은 인증 시점에만 외부 경로가 존재한다는 것이다.

외부에서 NAS로 들어오는 고정 포트를 새로 열지 않고, NAS에서 외부로 연결되는 임시 Tunnel을 사용한다.

왜 standard noVNC를 사용했나

원격 브라우저 UI는 처음부터 한 번에 정해지지 않았다.

처음 사용한 웹 기반 Firefox 컨테이너는 PC 환경에서는 문제가 없어 보였지만, 실제 Android Chrome에서 접속했을 때 검은 화면과 progress bar만 나타났다.

서버 로그를 확인해 보니 HTML과 JavaScript 파일은 내려갔지만, 실제 원격화면 연결을 시작하는 초기화가 휴대폰에서 진행되지 않았다.

같은 URL을 자동화된 모바일 Chrome 조건으로 테스트했을 때는 동작했기 때문에, 단순 네트워크 장애나 Tunnel 문제라고 보기 어려웠다.

결국 해당 UI를 계속 수정하기보다 구조를 단순화했다.

Chromium
-> Xvfb
-> x11vnc
-> standard noVNC

표준 noVNC는 모바일 환경에서 다음 기능을 직접 제공한다.

  • 원격 화면 canvas
  • touch/pointer 입력
  • 화면 크기 조정
  • 모바일 키보드 호출
  • WebSocket 기반 VNC 연결

실제 휴대폰에서 Chromium 화면이 표시되는 것까지 확인한 뒤 이 방식을 현재 운영 방식으로 확정했다.

일회용 URL을 사용하는 이유

임시 Tunnel 주소 자체도 무작위이지만, 그것만 보안 경계로 사용하지 않았다.

Tunnel 뒤에 임시 reverse proxy를 두고 긴 난수 경로 하나만 허용했다.

개념적으로는 다음과 같다.

https://temporary-host.example/<random-one-time-path>/...

다른 경로는 정상 원격 UI로 전달하지 않는다.

이 일회용 경로는 인증 세션을 시작할 때 새로 만들고, 로그인이 끝나면 proxy 설정과 함께 삭제한다.

따라서 운영 원칙은 다음과 같다.

필요할 때 생성
-> 짧게 사용
-> 로그인 완료 확인
-> 즉시 폐기

일회용 URL도 인증정보에 가까운 값으로 보고 Git, 문서, Issue 등에 남기지 않는다.

로그인 상태는 어디에 남기는가

외부 접속 경로는 제거하지만 브라우저 profile은 유지한다.

Chromium의 사용자 profile에는 정상 로그인 과정에서 생성된 쿠키와 사이트 상태가 저장된다.

이 profile은 NAS 로컬의 전용 상태 영역에만 두고 Git 추적 대상에서 제외한다.

중요한 구분은 다음과 같다.

Git
  코드
  설정 템플릿
  Runbook
  검증 가능한 운영 절차

NAS local state
  Chromium profile
  cookie/session
  일시적인 runtime 상태

Git에는 “어떻게 운영하는가”를 기록하고, 실제 인증 상태는 넣지 않는다.

다른 AI 세션에서도 같은 방식으로 사용하기

이 작업에서 기술 구현만큼 중요하게 본 부분은 운영 절차를 대화 기억에 의존하지 않는 것이었다.

한 채팅에서 어렵게 해결해도 다음 채팅에서 다시 처음부터 설명해야 한다면 운영 자동화로 보기 어렵다.

그래서 현재 방식은 별도 Runbook으로 정리하고, 프로젝트의 AI 작업 진입 문서와 전역 repository registry에서 해당 Runbook을 먼저 찾도록 연결했다.

사용자 입장에서는 다음 정도의 표현이면 충분하도록 만들었다.

잡코리아 인증할게

AI는 저장소에서 현재 Runbook을 찾고 임시 인증 세션을 연다.

로그인이 끝난 뒤에는:

잡코리아 로그인했어

라고 하면 외부 Tunnel과 일회용 경로를 닫고, 로그인 profile 보존 여부를 확인하는 흐름이다.

여기서 중요한 점은 “AI가 과거 대화를 기억한다”가 아니다.

실제 Source of Truth는 Git에 있는 운영 문서와 현재 runtime 증거다.

검증한 항목

최종 구조를 확정하기 전에 다음을 확인했다.

모바일 브라우저에서 noVNC 로드
WebSocket 연결
원격 화면 canvas 생성
Chromium 화면 표시
모바일 키보드 control 존재
실제 사용자 로그인
로그인 후 임시 Tunnel 제거
임시 proxy 제거
일회용 URL 제거
브라우저 profile 유지
로그인 도메인의 cookie 존재

쿠키 값이나 세션 값 자체는 검증 로그에 출력하지 않는다.

존재 여부나 개수처럼 인증정보를 노출하지 않는 수준의 메타데이터만 확인한다.

이 구조에서 자동화하지 않은 것

일부러 자동화하지 않은 영역도 있다.

  • 계정 ID/PW 입력
  • CAPTCHA 해결
  • MFA/추가 본인인증
  • 접근 제한 우회
  • 로그인 실패 시 무제한 재시도

이 부분은 사람이 직접 처리하는 것이 현재 목적에 더 맞다.

자동화의 목표는 모든 클릭을 없애는 것이 아니라, 사람이 해야 하는 일과 시스템이 반복해야 하는 일을 적절히 분리하는 것이라고 생각한다.

다음 단계

현재까지는 사람이 직접 로그인하고 NAS에 세션을 유지하는 경로를 만들었다.

다음 단계는 이 로그인 상태를 수집기와 안전하게 연결하는 것이다.

persistent Chromium profile
-> session validity check
-> authenticated collection
-> session 만료 시 AUTH_REQUIRED
-> 사용자가 휴대폰에서 재인증

수집기가 세션 만료를 정상 데이터로 오인하지 않고, 인증이 필요하면 명확하게 중단하는 것이 중요하다.

정리

이번 작업은 “로그인을 자동화하는 방법”보다 로그인을 자동화하지 않고도 전체 시스템을 자동화할 수 있는 방법에 가까웠다.

핵심 기준은 다음과 같다.

  • 비밀번호를 자동화 코드에 넣지 않는다.
  • 사용자가 직접 정상 인증한다.
  • 외부 접근은 필요할 때만 연다.
  • 인증이 끝나면 바로 닫는다.
  • 로그인 상태는 로컬에만 유지한다.
  • 운영 방법은 Git Runbook으로 남긴다.
  • 실제 동작 여부는 runtime에서 검증한다.

AI와 자동화를 사용할 때도 모든 단계를 AI에게 넘기는 것이 목표는 아니다.

사람이 해야 안전한 인증은 사람이 하고, 반복 가능한 운영과 검증은 시스템이 맡는 구조가 이 경우에는 더 적절했다.

전체 글 보기