세션 방식의 로그인 과정에 대해 설명해 주세요.

세션 방식 로그인은 사용자 인증 후 서버가 세션을 생성하고, 클라이언트에게 Session ID를 발급하여 이후 요청마다 인증 상태를 유지하는 방식입니다.

전체 흐름

[로그인]
1. 클라이언트 → 서버 : POST /login (아이디, 비밀번호)
2. 서버 : DB에서 사용자 조회 + 비밀번호 검증
3. 서버 : 세션 생성 (Session ID + 사용자 정보 저장)
4. 서버 → 클라이언트 : Set-Cookie: JSESSIONID=abc123

[인증이 필요한 요청]
5. 클라이언트 → 서버 : Cookie: JSESSIONID=abc123
6. 서버 : Session ID로 세션 저장소 조회 → 사용자 확인
7. 서버 → 클라이언트 : 응답 반환

[로그아웃]
8. 클라이언트 → 서버 : POST /logout
9. 서버 : 세션 무효화(삭제)
10. 서버 → 클라이언트 : Set-Cookie: JSESSIONID=; Max-Age=0

Java(Spring) 구현 예시

로그인

@PostMapping("/login")
public ResponseEntity<String> login(
        @RequestBody LoginRequest request,
        HttpSession session) {

    // 1. DB에서 사용자 조회
    Member member = memberRepository.findByLoginId(request.getLoginId())
            .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 사용자"));

    // 2. 비밀번호 검증 (BCrypt 등 해시 비교)
    if (!passwordEncoder.matches(request.getPassword(), member.getPassword())) {
        throw new IllegalArgumentException("비밀번호 불일치");
    }

    // 3. 세션에 사용자 정보 저장 (이 시점에 세션 생성 + JSESSIONID 발급)
    session.setAttribute("loginMember", member.getId());

    return ResponseEntity.ok("로그인 성공");
}

인증 확인

@GetMapping("/mypage")
public ResponseEntity<MemberResponse> myPage(HttpSession session) {

    // 세션에서 사용자 정보 조회
    Long memberId = (Long) session.getAttribute("loginMember");

    if (memberId == null) {
        throw new UnauthorizedException("로그인이 필요합니다");
    }

    Member member = memberRepository.findById(memberId)
            .orElseThrow(() -> new IllegalArgumentException("사용자 없음"));

    return ResponseEntity.ok(new MemberResponse(member));
}

로그아웃

@PostMapping("/logout")
public ResponseEntity<String> logout(HttpSession session) {

    // 세션 무효화 → 서버의 세션 데이터 삭제 + 쿠키 만료
    session.invalidate();

    return ResponseEntity.ok("로그아웃 성공");
}

HTTP 요청/응답 예시

// 로그인 요청
POST /login HTTP/1.1
Content-Type: application/json

{"loginId": "hong", "password": "1234"}

// 로그인 응답
HTTP/1.1 200 OK
Set-Cookie: JSESSIONID=abc123; Path=/; HttpOnly; Secure

// 이후 인증 요청
GET /mypage HTTP/1.1
Cookie: JSESSIONID=abc123

세션 저장소의 내부 구조

세션 저장소 (서버 메모리 / Redis)
┌──────────────────────────────────────────┐
│ Session ID      │ 세션 데이터             │
├──────────────────────────────────────────┤
│ abc123          │ {loginMember: 1}        │
│ def456          │ {loginMember: 7}        │
│ ghi789          │ {loginMember: 15}       │
└──────────────────────────────────────────┘

보안 고려사항

위협대응 방법
세션 하이재킹 (Session ID 탈취)HttpOnly, Secure, SameSite 쿠키 속성 설정
세션 고정 공격 (Session Fixation)로그인 성공 시 기존 세션 무효화 후 새 Session ID 발급
무차별 대입Session ID를 충분히 길고 랜덤하게 생성 (Tomcat 기본 제공)
세션 만료 미처리session.setMaxInactiveInterval(1800) 등 타임아웃 설정
// Spring Security - 세션 고정 공격 방어 (기본 활성화)
@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .sessionManagement(session -> session
                .sessionFixation().changeSessionId()   // 로그인 시 새 Session ID 발급
                .maximumSessions(1)                    // 동시 로그인 1개로 제한
                .maxSessionsPreventsLogin(false)        // 기존 세션 만료 처리
            );
        return http.build();
    }
}

면접 포인트

CSLOG에서 보기