Cheondi
개발 · 보안

테스트 로그인 기록이 유령처럼 남았다

로그아웃 뒤에도 남은 테스트 계정 흔적을 저장소와 세션 경계별로 추적한 기록입니다.

  • #login
  • #session
  • #local-storage

테스트 계정으로 로그인한 뒤 로그아웃하고 다른 계정으로 들어갔는데 이전 계정의 일부 정보가 잠깐 보였다. 아이디 입력창에도 과거 값이 다시 나타났다. 로그아웃 함수에서는 세션 값을 지우고 있었기 때문에 처음에는 브라우저 자동 완성 문제라고만 생각했다.

확인해 보니 로그인과 관련된 값은 한 곳에만 있지 않았다. Unity 메모리, 로컬 설정, 브라우저 저장소, 쿠키, 화면 컴포넌트가 각각 이전 상태를 들고 있었다.

로그아웃의 범위를 목록으로 만들었다

로그아웃할 때 무엇을 지워야 하는지 역할별로 나눴다.

인증 정보     : 세션·토큰 만료
사용자별 캐시 : 계좌·권한·최근 조회 데이터 제거
화면 상태     : 선택 항목과 표시 값 초기화
개인 설정     : 정책에 따라 유지하거나 계정별 분리

모든 로컬 데이터를 지우면 테마 같은 개인 설정까지 사라지고, 인증 정보만 지우면 이전 사용자 데이터가 남았다. 삭제 정책이 필요했다.

키 이름에 사용자 경계를 넣었다

공용 키 하나에 최근 화면 상태를 저장하면 계정이 바뀌어도 같은 값을 읽었다. 사용자별로 유지해야 하는 설정은 내부 식별자를 포함한 네임스페이스로 나눴다.

string UserKey(string userId, string name)
    => $"user:{HashForLocalKey(userId)}:{name}";

식별자를 그대로 키에 노출하지 않고 로컬 용도의 안정적인 값으로 변환했다. 서버 권한 판단에는 이 로컬 키를 사용하지 않았다.

자동 완성과 앱 저장을 구분했다

브라우저가 기억한 입력 값과 앱이 저장한 자동 로그인 정보는 겉으로 비슷했다. 개발자 도구에서 저장소와 쿠키를 확인하고, 앱 로그에는 어느 저장 경로에서 값을 복원했는지만 남겼다. 비밀번호나 토큰 자체를 출력하지 않았다.

로그아웃 뒤 새로고침, 브라우저 재시작, 다른 계정 로그인 순서로 확인하니 어느 계층에 값이 남는지 분리할 수 있었다.

삭제도 데이터 설계의 일부였다

처음에는 저장 기능을 만들 때 어떻게 읽을지만 생각했다. 사용자 전환을 겪고 나니 언제, 어디까지 지워야 하는지가 같은 무게의 설계라는 걸 알았다. 특히 공유 기기에서는 이전 사용자 흔적이 잠깐 보이는 것만으로도 문제가 될 수 있었다.

유령처럼 보였던 기록은 실제로 여러 저장소의 수명이 달라 생긴 결과였다. 이후 사용자별 데이터를 추가할 때는 저장 위치와 함께 로그아웃, 계정 전환, 만료 시점의 정리 규칙도 적어두게 됐다.