공지사항

자주하는 질문

자주하는 질문 목록

자주하는 질문 목록


  • 질문내용 질문사항은 어떻게 입력합니까?
  • 질문내용 영문 인보이스가 필요한가요?
  • 질문내용 자체 보험 대신 고객 보험을 사용할 수 있나요?
  • 질문내용 현금 영수증 발행이 되나요?
  • 질문내용 도착 후 서명 사본을 받을 수 있나요?
  • 질문내용 위로 적재가 불가한 화물도 가능한가요?
  • 질문내용 상차지 출입증 발급이 필요한데 도와주나요?
  • 질문내용 도서산간 추가비가 있나요?
  • 질문내용 상담 가능 시간은 언제인가요?
  • 질문내용 API로 송장 연동이 되나요
  • 질문내용 거래명세서 양식은 어디서 받나요?
  • 질문내용 보관 후 출고까지 맡길 수 있나요?
  • 질문내용 포장재 회수도 가능한가요?
  • 질문내용 반품 회수 서비스가 있나요
  • 질문내용 운송 계약서를 체결할 수 있나요?
FAQ 내용

답변 내용

운송서비스
2025-11-04
질문사항은 어떻게 입력합니까?

제공해주신 파일들을 바탕으로 "세션 만료 후 재로그인 시 403 (Forbidden) 토큰 불일치 에러"가 발생하는 원인을 종합적으로 분석하고 해결책을 제시해 드립니다.

1. 문제의 핵심 원인: 3-Way 충돌

현재 구조는 3개의 다른 컴포넌트가 각기 다른 시점에 세션과 CSRF 토큰을 관리하려 하면서 충돌하고 있습니다.

  1. CsrfFilter (서블릿 필터): 가장 먼저 실행됩니다. POST /member/login 요청을 받으면, 컨트롤러 실행 전에 ensureTokenInSession을 호출해 새 세션(A)을 만들고 새 토큰(Token_A)을 세션에 저장합니다.

  2. LoginInterceptor (스프링 인터셉터): CsrfFilter 다음에 실행됩니다. 이 인터셉터는 "sessionMemberInfo"가 세션에 있는지 확인합니다. 하지만 이 시점엔 아직 MemberController가 실행되지 않았으므로 "sessionMemberInfo"는 null입니다.

  3. MemberController (컨트롤러): 인터셉터 다음에 실행됩니다. 로그인 성공 시 session.setAttribute("sessionMemberInfo", ...)를 호출합니다. 이때 스프링(또는 서블릿 컨테이너)은 **세션 고정 공격(Session Fixation)**을 방어하기 위해 기존 세션(A)을 무효화하고 **완전히 새로운 세션(B)**을 생성할 수 있습니다.

에러 발생 시나리오 (403 Forbidden):

  1. 세션 만료: 사용자가 페이지에 머무는 동안 서버 세션이 만료됩니다. (브라우저의 XSRF-TOKEN 쿠키(Token_Old)는 남아있습니다.)

  2. 동작 실패 (401): 사용자가 저장을 누르면(POST /admin/..), CsrfFilter가 세션이 없어 401을 반환합니다. (이때 LoginInterceptor가 먼저 401을 반환할 수도 있습니다.)

  3. 로그인 시도:

    • loginSubmit.js가 POST /member/login을 호출합니다.

    • CsrfFilter가 요청을 받고, isLogin=true로 인지합니다.

    • ensureTokenInSession이 실행되어 **새 세션(A)**을 만들고 CSRF_TOKEN 속성에 **Token_New**를 저장합니다.

    • chain.doFilter로 다음 단계(인터셉터)로 넘깁니다.

  4. 컨트롤러 실행 및 세션 교체:

    • (LoginInterceptor가 /member/login을 제외(exclude)했다고 가정하고) MemberController가 실행됩니다.

    • 로그인 성공 후 session.setAttribute("sessionMemberInfo", ...)가 호출됩니다.

    • 이때 세션 고정 방어가 발동하여, CsrfFilter가 만든 세션(A)이 파괴되고, 새로운 세션(B)이 생성됩니다.

    • "sessionMemberInfo"는 **세션(B)**에 저장됩니다.

    • 문제: CsrfFilter가 세션(A)에 저장했던 CSRF_TOKEN 속성(Token_New)은 세션(B)로 복사되지 않고 소실됩니다.

  5. 토큰 동기화 실패:

    • MemberController가 종료되고 CsrfFilter로 제어권이 돌아옵니다.

    • syncTokenCookieIfSessionValid가 실행됩니다.

    • request.getSession(false)는 이제 **세션(B)**를 반환합니다.

    • session.getAttribute(CSRF_ATTR)를 호출하지만, **세션(B)**에는 이 속성이 없으므로 null이 반환됩니다.

    • 결과적으로 Set-Cookie: XSRF-TOKEN=... 헤더가 전송되지 않습니다.

  6. 403 발생:

    • 브라우저는 여전히 만료된 XSRF-TOKEN 쿠키(Token_Old)를 가지고 있습니다.

    • 사용자가 다시 POST /admin/.. 요청을 보냅니다.

    • JS는 Token_Old를 헤더에 실어 보냅니다.

    • CsrfFilter는 세션(B)(로그인된 유효한 세션)를 확인합니다.

    • sessionToken = session.getAttribute(CSRF_ATTR) -> null입니다.

    • requestToken은 Token_Old입니다.

    • if (sessionToken == null) 조건에 걸려 403 Forbidden을 반환합니다


간편산출 간편산출 전화상담 전화상담 카톡상담 카톡상담
|