본문 바로가기

Spring Boot

쿠키와 세션 기반 인증 : 세션 기반 인증

세션(Session)

 

 - 세션의 정의, 배경

 - 세션이 필요한 이유(HTTP의 무상태성 보완)

 - 세션의 특징, 구조, 동작 과정 등

 - 세션 기반 인증 워크플로우를 다이어그램, 예제로 익히기

 - 실무에서 안전하게 세션을 관리하는 방법(만료, 보안 옵션, 로그아웃) 알기

 


 

세션의 이해

1) 정의

세션(Session)은 클라이언트(사용자)가 서버에 접속한 순간부터 접속을 끝을 때까지의 연결상태를 의미함

웹에서는 HTTP 프로토콜이 무상태성(Stateless)이므로, 서버가 사용자의 상태를 기억하지 못함

따라서 로그인 상태 유지, 장바구니 정보, 사용자 맞춤 화면 등을 제공하기 위해서 세션이 필요함

즉, 세션은 사용자의 상태 정보를 서버에 저장해 두고, 이를 세션ID(Session ID)라는 키로 식별하는 방식임

 - > 세션은 서버가 기억하는 사용자의 임시 신분증이다

 

2) 특징

 - 서버 중심 관리 : 사용자의 로그인 여부, 권한, 장바구니 정보 등을 서버가 직접 보관함

 - 클라이언트는 세션 ID만 보관함 : 브라우저는 세션 자체가 아닌 세션을 가리키는 고유 ID를 쿠키에 저장함

 - 만료 가능 : 일정기간 요청이 없으면 세션을 종료하거나, 최대 사용시간을 설정할 수 있음

 - 보안 의존성 : 세션ID가 유출되면 사용자 정보가 탈취될 수 있음. 따라서 세션ID를 안전하게 보호하는게 중요함

저장위치 서버(메모리, DB, Redis 등..)
클라이언트 역할 세션ID를 쿠키에 저장하여 요청마다 전달함
만료관리 TTL(Time-to-Live), 유휴/절대 타임아웃
보안 이슈 세션ID 탈취, 세션고정(Session Fixation) 공격

 

 

세션의 동작 방식

1) 세션 생성과 전달

1. 사용자가 로그인 시 서버는 아이디/비밀번호 검증을 수행함

2. 검증에 성공하면 서버는 새로운 세션 객체(Session)를 생성하고, 사용자 ID와 관련 정보를 세션 저장소에 저장

3. 서버는 해당 세션을 식별할 수 있는 세션ID를 생성

4. 세션ID를 Set-Cookie 헤더에 담아브라우저에 전달

HTTP/1.1 200 OK
Set-Cookie: 
SESSION=abc123; // 서버가 발급한 세션 ID 
Path=/; // 패스
HttpOnly; // 자바스크립트 접근 방지(XSS 방어)
Secure; // HTTPS에서만 전송함
Max-Age=1800; // 세션 유지 시간

 

브라우저가 이 Set-Cookie를 저장하고, 이후 동일한 도메인 요청마다 자동으로 전송한다고 함

 

2) 세션 확인 과정

1. 사용자가 보호된 페이지에 접근하면 브라우저는 자동으로 요청에 Cookie헤더를 포함함(Post)

2. 서버는 요청 헤더의 세션ID(abc123 등..)를 확인함

3. 서버는 세션 저장소에서 해당 세션 ID를 찾아서 사용자 정보를 복원함

4. 세션이 유효하면 요청을 정상 처리하고 응답함(Response)

GET /mypage HTTP/1.1
Host: example.com
Cookie: SESSION=abc123

 

 

3) 동작 워크플로우 다이어그램

어렵긴한데 보고 이해하는게 중요하다..

 

사용자가 브라우저에 로그인 정보(ID, PW) 입력 - > 브라우저가 서버에 로그인 요청 - > 서버가 사용자 검증 

- > 서버가 세션저장소에 세션 생성 및 저장 - > 서버가 브라우저에 쿠키를 줌 - > 브라우저는 쿠키를 저장함

- > 사용자가 브라우저에 보호된 페이지를 요청함 -> 브라우저가 서버에 쿠키에 맞는 세션을 요청함 - >

- > 서버가 세션저장소에서 세션ID를 조회함 - > 세션에 맞는 정보를 서버에 반환함 - > 서버가 브라우저에 요청페이지를 응답함

 

 

4) Set-Cookie vs Cookie의 차이점?

헤더 방향 설명 예시
Set-Cookie 서버 - > 브라우저 서버가 쿠키를 생성/수정하도록 지시함 Set-Cookie: SESSION=abc123;
Path=/; HttpOnly; Secure
Cookie 브라우저 - > 서버 브라우저가 저장한 쿠키값을 전송함 Cookie: SESSION=abc123

 

 

세션 관리 구현 예시

1) 디렉토리 구조 예시

src/main/java/auth

Session.java // 세션의 객체 정의

SessionManager.java // 세션 생성/조회/만료 관리

CookieUtil.java // 쿠키 파싱/생성 유틸

AuthController.java // 로그인, 로그아웃 엔드포인트

 

2) 예시

public class Session { // 세션 객체를 정의함
	private String id; // 세션ID
    private String userId; // 사용자의 ID
    private long expiresAt; // 만료 시간
    
    // setter
    public Session(String id, String userId, long ttlSeconds) {
    	this.id = id;
        this.userId = userId;
        this.expiresAt = System.currentTimeMillis() + ttlSeconds * 1000;
    }
    
    public boolean isExpired() {
    	return System.currentTimeMillis() > expiresAt;
    }
    
    public String getUserId() {
    	return userId;
    }
    
    public String getId() {
    	return id;
    }
}

 

// 세션 관리자
public class SessionManager {
	private Map<String, Session> store = new ConcurrentHashMap<>();
    
    // 세션 생성
    publicc Session create(String userId, long ttlSeconds) {
    	String id = UUID.randomUUID().toString(); // 세션 ID를 생성
        Session session = new Session(id, userId, ttlSeconds); // 세션 인스턴스 생성
        store.put(id, session); // store에 저장, session의 id와 store의 id는 같다
        return session;
    }
    
    // 세션 조회
    public Session find(String id) {
    	Session session = store.get(id);
        if(session == null || session.isExpired()) {
        	stroe.remove(id);
            return null;
        }
        return session;
    }
    
    // 세션 무효화
    public void invalidate(String id) {
    	store.remove(id);
    }
}

 

 

세션 기반 인증의 보안 고려사항

세션 기반 인증은 편리하지만, 보안 위협에 취약할 수 있다. 서버측에서 관리하지만 털리면 큰일나기 때문

 

1) 세션ID 보안

 - 랜덤성 : 세션ID는 충분히 긴 난수(UUID v4, 난수 발생기 등등..)를 사용해야함

 - 예측 불가능성 : 단순히 증가하는 숫자나 시간 기반 ID는 공격자가 쉽게 예측할 수 있음

 - 쿠키 보안 속성

    - Secure : HTTPS 연결에서만 전송하게끔함

    - HttpOnly : JavaScript로 쿠키의 접근을 차단함 - > XSS 완화

    - SameSite : 크로스 사이트 요청을 제한함 - > CSRF 완화

 - 고유성 보장 : 동일한 세션 ID가 동시에 재발급되지 않도록 보장함

Set-Cookie: SESSION=abc123xyz; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=1800

 

2) 세션 만료 정책

 - 유휴 타임아웃(Idle TimeOut) : 일정시간 요청이 없으면 세션을 자동으로 만료시킴

 - 절대 타임아웃(Absolute TimeOut) : 세션이 생성된지 일정 시간이 지나면 무조건 만료시킴

 - 강제 로그아웃 : 관리자가 특정 사용자의 세션을 강제로 만료시킬 수 있어야함

 

3) 세션 고정(Session Fixation) 방지

 - 문제점 : 공격자가 미리 발급받은 세션 ID를 피해자에게 강제로 사용하게 하면,

                로그인 후에도 공격자가 동일 세션을 이용할 수 있음

 - 대책 : 

    - 로그인 성공시 새로운 세션ID를 무조건 재발급하게 함

    - 권한 상승(일반 사용자 - > VIP 등등..) 시에도 세션ID를 다시 생성하게끔 함

// 로그인이 성공하면
Session newSession = sessionManager.create(userId, 1800);
response.addHeader("Set-Cookie", "SESSION=" + newSession.getId() + "; HttpOnly; Secure; SameSite=Lax");

 

 

4) 로그아웃 처리

 - 서버 측 세션을 무효화함 : 세션 저장소에서 해당 세션 ID를 삭제시킴

 - 클라이언트 쿠키 만료 지시 : Max-Age=0 또는 Expires 속성을 활용해서 브라우저 쿠키를 제거함

 - 즉시 반영 : 로그아웃 요청 즉시 세션이 무효화되어야하며, 남아있는 요청이 더이상 인증되지 않아야한다.

로그아웃 처리 시 세션 쿠키 삭제

 

5) 추가 고려사항

 - 동시 세션 제어 : 동일 사용자가 여러 기기에서 로그인할 경우, 정책적으로 허용/제한할지 결정하기

 - 세션 하이재킹 대응 : 비정상적인 위치(외국 IP, User-Agent 등등..)에서 세션 접근시 알림 또는 강제 만료처리하게끔 하기

 - 로그 및 모니터링 : 로그인/로그아웃, 세션 만료, 실패 시도 등을 로깅하여 추적 가능성 확보하기

 - 전송 계층 보안 : 세션 쿠키는 반드시 TLS(HTTPS)를 통해서만 전송하게 하기

 

 

세션 ID 보안 : 예측 불가능한 난수 + Secure/HttpOnly/SameSite 속성

만료 정책 : 유휴 타임아웃 + 절대 타임아웃 병행하기

세션 고정 방지 : 로그인/권한 상승시 새 세션 ID를 발급하기

로그아웃 처리 : 서버 세션 무효화 + 쿠키 만료 지시하기

추가 고려사항 : 동시 세션 제어, 세션 하이재킹 탐지, 로깅/모니터링하기