Cheondi
개발 · 보안

테스트 로그인 잔여 기록

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

  • #login
  • #session
  • #local-storage

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

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

로그아웃 데이터 정리 범위

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

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

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

사용자 경계를 포함한 캐시 키

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

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

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

브라우저 자동 완성과 앱 저장의 구분

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

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

데이터 삭제 정책

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

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

추가 구현 기준

나중에 같은 증상을 다시 만나지 않으려고 문서에 적힌 기준으로 구현을 한 번 더 정리했다.

OWASP ASVS와 API Security 기준을 따라 다시 보면 화면에서 숨겼다는 사실은 권한 검사가 아니다. 계좌나 사용자 식별자를 클라이언트가 보내더라도 서버는 인증 주체가 그 객체에 접근할 수 있는지 매 요청에서 확인해야 한다.

클라이언트의 역할은 권한을 결정하는 것이 아니라 잘못된 조작을 줄이고, 거부 응답을 이전 데이터와 섞지 않으며, 민감한 정보를 로그나 저장소에 남기지 않는 데 가깝다.

다음에 테스트 로그인 잔여 기록 같은 문제를 보면 아래 순서부터 확인하려고 한다.

  • 익명·인증 중·인증됨·만료 상태
  • 재시도 가능한 오류와 사용자 입력 필요 오류
  • 토큰 폐기와 화면 초기화 순서
  • 동시에 도착한 만료 응답의 단일 처리

식별자 형식을 어렵게 만들거나 메뉴를 감추는 방법은 서버의 객체 수준 권한 검사를 대체하지 못한다.

공식 참고 자료