[웹 보안] 보안 로직 추가 후 로그인이 즉시 풀리는 현상 (Session Fixation 방어와 invalidate()의 함정)

2026. 1. 7. 22:58·◈ Study/웹 보안(Web Security)🔐
728x90
반응형


- 보안 로직 추가 후 로그인이 즉시 풀리는 현상

최근 로그인 시 보안 강화를 위해 세션 고정(Session Fixation) 공격 방어 로직을 추가하던 중, 로그인이 성공하자마자 풀려버리는(인증이 유지되지 않는) 이슈를 겪었습니다.

겉보기엔 올바른 보안 로직 같아 보이지만, HttpSession의 생명주기와 인증 컨텍스트 처리 방식에 대한 오해에서 비롯된 흔한 실수였습니다. 해당 문제의 원인과 해결 방법을 정리하여 공유합니다.

1. 문제 상황

로그인 프로세스 도중, 세션 하이재킹을 방지하기 위해 기존 세션을 파기하고 새로운 세션을 발급하는 아래 코드를 추가했습니다. 그런데 이 코드가 실행된 직후 클라이언트가 비로그인 상태가 되는 현상이 발생했습니다.

// 문제의 코드: 세션 고정 공격 방어 로직
HttpSession currentSession = request.getSession(false);
if (currentSession != null) {
    try {
        // 기존 세션을 무효화 (여기서 문제 발생)
        currentSession.invalidate(); 
    } catch (IllegalStateException e) {
        // ignore
    }
}

// 새 세션 생성
currentSession = request.getSession(true);

2. 원인 분석

핵심 원인은 "세션 객체의 생명주기가 종료되면서, 그 안에 저장된 인증 정보도 함께 소멸했기 때문"입니다.

웹 애플리케이션의 일반적인 로그인 흐름은 다음과 같습니다.
  1. 인증 성공: ID/PW 검증 후, 서버는 사용자 정보가 담긴 인증 객체를 HttpSession에 저장합니다.
  2. 세션 무효화 (invalidate()): 위 코드에서 invalidate()를 호출하는 순간, 1번에서 저장한 인증 객체를 포함한 모든 세션 속성(Attribute)이 메모리에서 삭제됩니다.
  3. 새 세션 생성: request.getSession(true)로 얻은 세션은 완전히 비어있는 깡통 세션입니다.
  4. 결과: 서버 입장에서 이 사용자는 인증 정보를 잃어버린 '익명 사용자'일 뿐입니다.

 

즉, "방어벽을 높이려다 집 열쇠까지 버리고 새 집으로 이사 간 꼴"이 된 것입니다.

 


3. 해결 방법

방법 A. Servlet 3.1+ changeSessionId() 사용

가장 깔끔하고 현대적인 방법입니다. Servlet 3.1(Tomcat 8 이상)부터는 세션 내부의 데이터(Attribute)는 그대로 유지하면서, Session ID만 교체해주는 메서드를 제공합니다.

HttpServletRequest request = ...; 

if (request.getSession(false) != null) {
    // 기존 데이터(인증 정보 등)는 유지하고 ID만 변경하여 세션 고정 공격 방어
    request.changeSessionId(); 
}

방법 B. Spring Security 설정 활용

Spring Security를 사용 중이라면 비즈니스 로직에 굳이 세션 처리 코드를 넣을 필요가 없습니다. 프레임워크 레벨에서 이를 지원합니다.

// SecurityConfig 설정
http.sessionManagement()
    .sessionFixation().changeSessionId(); // 기본값은 migrateSession()

방법 C. 수동 마이그레이션 (Legacy 환경)

changeSessionId()를 사용할 수 없는 구버전 환경이라면, invalidate() 호출 전에 속성들을 백업하고 복원하는 절차가 필요합니다.

// 1. 기존 속성 백업
Map<String, Object> attributes = new HashMap<>();
Enumeration<String> names = oldSession.getAttributeNames();
while (names.hasMoreElements()) {
    String name = names.nextElement();
    attributes.put(name, oldSession.getAttribute(name));
}

// 2. 세션 재생성
oldSession.invalidate();
HttpSession newSession = request.getSession(true);

// 3. 속성 복구 (인증 정보 포함)
attributes.forEach(newSession::setAttribute);
728x90
반응형
'◈ Study/웹 보안(Web Security)🔐' 카테고리의 다른 글
  • [SSL 인증서] 왜 비싼 돈 들여 기업 인증(OV/EV)을 하는가? [SSL 인증서 선정 방법]
  • [SSL 인증서] 수백만 원짜리 SSL 인증서, 무료(Let's Encrypt)와 암호화 기술은 똑같다? [DV, OV, EV의 차이]
  • [정보보안] SSL VPN을 통한 로컬 바이러스의 사내망 전파, 기술적으로 가능한가? (Feat. BlueMax 아키텍처)
  • [보안 분석] "VS Code 쓰면 털린다?"... 인텔리제이/이클립스로 갈아타야 할까?
예르미(yermi)
예르미(yermi)
끊임없이 제 자신을 계발하는 개발자입니다👨🏻‍💻
  • 예르미(yermi)
    예르미의 코딩노트
    예르미(yermi)
  • 전체
    오늘
    어제
    • 분류 전체보기 (987)
      • ◎ Java (133)
        • Java☕ (93)
        • JSP📋 (26)
        • Applet🧳 (6)
        • Interview👨🏻‍🏫 (8)
      • ◎ JavaScript (48)
        • JavaScript🦎 (25)
        • jQuery🌊 (8)
        • React🌐 (2)
        • Vue.js🔰 (6)
        • Node.js🫒 (3)
        • Google App Script🐑 (4)
      • ◎ HTML5+CSS3 (17)
        • HTML5📝 (8)
        • CSS3🎨 (9)
      • ──────────── (0)
      • ▣ Framework (67)
        • Spring🍃 (36)
        • Spring Boot🍀 (12)
        • Bootstrap💜 (3)
        • Selenium🌕 (6)
        • MyBatis🐣 (10)
      • ▣ Tools (47)
        • API🎯 (18)
        • Library🎲 (15)
        • JitPack🚀 (3)
        • Jenkins👨🏻 (7)
        • Thymeleaf🌿 (4)
      • ▣ Server (30)
        • Apache Tomcat🐱 (14)
        • Apache HTTP Server🛡️ (1)
        • Nginx🧶 (7)
        • OracleXE💿 (4)
        • VisualSVN📡 (4)
      • ▣ Infra & DevOps (5)
        • LGTM Stack🔭 (5)
      • ▣ OS : 운영체제 (18)
        • cmd : 명령프롬프트💻 (10)
        • Linux🐧 (8)
      • ▣ SQL : Database (56)
        • Oracle SQL🏮 (26)
        • PL SQL💾 (9)
        • MySQL🐬 (6)
        • MariaDB🦦 (6)
        • H2 Database🔠 (3)
        • SQL 실전문제🐌 (6)
      • ────────── (0)
      • ◈ Human Project (86)
        • Mini : Library Service📚 (15)
        • 화면 설계 [HTML]🐯 (10)
        • 서버 프로그램 구현🦁 (15)
        • Team : 여수어때🛫 (19)
        • Custom : Student🏫 (9)
        • Custom : Board📖 (18)
      • ◈ Yermi Project (40)
        • 조사모아(Josa-moa)📬 (5)
        • Riddle-Game🧩 (6)
        • 맛있을 지도🍚 (2)
        • 어디 가! 박대리!🙋🏻‍♂️ (5)
        • 조크베어🐻‍❄️ (4)
        • Looks Like Thirty🦉 (2)
        • Toy Project💎 (12)
        • 오픈소스 파헤치기🪐 (4)
      • ◈ Refactoring (15)
        • Mini : Library Service📚 (8)
        • 서버 프로그램 구현🦁 (1)
        • Team : 여수어때🛫 (0)
        • 쿼리 튜닝일지🔧 (6)
      • ◈ Coding Test (80)
        • 백준(BOJ)👨🏻‍💻 (71)
        • 프로그래머스😎 (2)
        • 코드트리🌳 (7)
      • ◈ Study (129)
        • 기초튼튼 개발지식🥔 (25)
        • HTTP 웹 지식💡 (4)
        • 클린코드(Clean Code)🩺 (1)
        • 디자인패턴(GoF)🥞 (12)
        • 알고리즘(Algorithm)🎡 (14)
        • 다이어그램(Diagram)📈 (4)
        • 파이썬(Python)🐍 (16)
        • 에러노트(Error Note)🧱 (34)
        • 웹 보안(Web Security)🔐 (11)
        • 인공지능 AI🛸 (8)
      • ◈ 공부모임 (55)
        • 혼공학습단⏰ (18)
        • 코드트리 챌린지👊🏻 (2)
        • 개발도서 100독👟 (8)
        • 나는 리뷰어다🌾 (15)
        • 국가기술자격 서포터즈🌻 (12)
      • ◈ 자격증 공부 (37)
        • 정보처리기사🔱 (16)
        • 정보처리산업기사🔅 (9)
        • 정보보안기사⚜️ (0)
        • 컴퓨터활용능력 1급📼 (12)
      • ─────────── (0)
      • ◐ 기타 (124)
        • 알아두면 좋은 팁(tip)✨ (46)
        • 개발자의 일상🎈 (55)
        • 개발도서 서평🔍 (10)
        • 개발관련 세미나🎤 (2)
        • 블로그 꾸미기🎀 (9)
        • 사도신경 프로젝트🎚️ (2)
  • 인기 글

  • 최근 댓글

  • 반응형
    250x250
  • 태그

    백준
    Oracle
    Project
    백준 티어
    코딩
    CSS
    프로그래밍
    자바스크립트
    spring
    Error Note
    javascript
    꿀팁
    Java
    html
    코딩 테스트
    SQL
    BOJ
    jsp
    일상
    Database
  • hELLO· Designed By정상우.v4.10.3
예르미(yermi)
[웹 보안] 보안 로직 추가 후 로그인이 즉시 풀리는 현상 (Session Fixation 방어와 invalidate()의 함정)
상단으로

티스토리툴바