세션과 메모리 캐시를 엮어 콜백 인증 데이터를 안전하게 지키는 방법

Intro

  • 저는 본인확인 콜백을 다루면서 두 번이나 세션이 비는 사고를 맞았어요.
  • 브라우저는 GET으로, 일부 모바일 브라우저는 POST로 돌아오고, 로드밸런서는 세션을 가끔 잊어버리더군요.
  • 그래서 세션만 믿지 말고 메모리 캐시를 함께 쓰는 하이브리드 전략을 직접 설계했습니다.

핵심 아이디어 요약

  • 토큰 기준으로 세션과 프로세스 메모리에 동시에 데이터를 저장합니다.
  • 콜백이 들어오면 메모리 캐시를 먼저 확인하고, 없으면 세션을 폴백합니다.
  • 1시간짜리 만료 타이머를 두어 인증 정보가 무한정 남지 않도록 합니다.

준비와 선택

  • 로드밸런서(ALB) 뒤에서 세션 스티키가 잘 걸리지 않는다는 걸 인정하고, 세션만으로는 불안하다는 결론을 냈습니다.
  • Redis까지 들고 오기엔 과한 상황이라, 최소한의 안전장치로 Node.js 프로세스 메모리를 활용하기로 했습니다.
  • 토큰 만료를 자동으로 돌리기 위해 setInterval 기반 청소 루틴을 추가했습니다.

구현 여정

  • Step 1: 토큰 저장 구조 정의
    tokenStorage라는 Map을 만들고, 복호화를 위해 필요한 key, iv, hmac_key, req_no를 묶어 저장합니다.
  • Step 2: 만료 타이머 설정
    1시간(3,600초)을 상수로 두고, 매분 실행되는 청소 루틴을 붙였습니다. 덕분에 메모리 누수 걱정을 덜었죠.
const TOKEN_EXPIRE_TIME = 60 * 60 * 1000; // 1시간
setInterval(() => {
  const now = Date.now();
  for (const [token_version_id, data] of tokenStorage.entries()) {
    if (now - data.created_at > TOKEN_EXPIRE_TIME) {
      tokenStorage.delete(token_version_id);
      console.log(`만료된 토큰 삭제: ${token_version_id}`);
    }
  }
}, 60000);
  • Step 3: 발급 시 이중 저장
    토큰을 발급할 때 세션과 tokenStorage에 동시에 넣습니다. 이중화 덕분에 콜백이 다른 노드로 튀더라도 최소한 한 곳에서 데이터를 건질 수 있습니다.
  • Step 4: 콜백 처리에서 폴백 순서 설계
    /checkplus_success에서는 먼저 메모리 캐시를 확인하고, 없을 때만 세션으로 내려갑니다. 로그를 남겨 두 경로 중 어떤 것을 탔는지 추적했습니다.
const tokenData = tokenStorage.get(token_version_id);
let key: string, iv: string, hmac_key: string, req_no: string;

if (tokenData) {
  ({ key, iv, hmac_key, req_no } = tokenData); // 캐시 히트
} else {
  key = req.session.key || ""; // 세션 폴백
  iv = req.session.iv || "";
  hmac_key = req.session.hmac || "";
  req_no = req.session.req_no || "";
}
  • Step 5: 디버깅 로그와 정리
    무결성 검증에 실패하면 자세한 로그를 남기고, 성공하면 세션 값을 정리했습니다. 세션 누수로 인한 이상 동작을 막는 마지막 장치였습니다.
  • 캐시 청소 주기가 너무 짧은 건 아닌지 확인하려고, 저는 GPT에게 시뮬레이션 로직을 물어봤고 10분 주기로도 충분하지만 1시간이 사용자 경험상 든든하다는 판단을 다시 확인했습니다.

결과와 회고

  • 세션만 쓸 때 겪었던 “토큰을 찾을 수 없습니다” 오류가 현저히 줄어들었습니다.
  • 요청마다 저장소 상황을 로그로 남겨두니, 운용 중 문제를 재현하기도 쉬워졌습니다.
  • 다만 여러 프로세스나 서버로 스케일 아웃하면 Map만으로는 부족하니, 다음에는 Redis나 DynamoDB 같은 외부 스토리지를 연동할 예정입니다.
  • 여러분은 콜백 인증 데이터를 어디에 저장하시나요? 로컬 세션을 계속 쓰는지, 아니면 별도 캐시를 두고 계신지 궁금합니다.

Reference

연결문서