Experience/LG CNS AM Inspire Camp 1기

[LG CNS AM Inspire Camp] 16. Spring Security (with Session, Cookie, JWT)

chillmyh 2025. 2. 10. 19:36

 

1. Spring Security 

Spring Security는 애플리케이션의 보안 기능을 제공하는 강력한 프레임워크이다. 인증(Authentication)과 권한 부여(Authorization)를 처리하는 데 사용되며, 쿠키, 세션, JWT 기반 인증을 모두 지원한다.

2. 쿠키(Cookie)와 세션(Session)

2.1. 쿠키(Cookie)

쿠키는 클라이언트(브라우저)에 저장되는 작은 데이터 조각으로, 서버가 사용자 정보를 저장하고 필요할 때 클라이언트에서 전송받을 수 있도록 한다.

 

쿠키 특징

  • HTTP 요청 및 응답 헤더를 통해 주고받음
  • 클라이언트(브라우저)에 저장됨
  • 만료 시간이 지나거나 삭제될 때까지 유지됨
  • 보안에 취약하므로 중요한 정보는 저장하면 안 됨

안전한 쿠키 관리 방법

  1. 중요한 정보를 포함하지 않도록 설정
  2. 만료 시간(Expires)과 지속 시간(Max-Age)을 최소한으로 설정
  3. HttpOnly 속성을 활성화하여 JavaScript에서 접근하지 못하도록 함
  4. Secure 속성을 활성화하여 HTTPS 통신에서만 전송하도록 제한

2.2. 세션(Session)

세션은 서버 측에서 관리되는 사용자 상태 저장 방식이다. 사용자가 로그인하면 세션 ID가 부여되고, 이후 요청마다 세션 ID를 이용해 인증된 사용자임을 확인할 수 있다.

 

세션 특징

  • 서버에서 사용자 정보를 저장하고 관리
  • 클라이언트는 세션 ID만 유지
  • 서버 리소스를 소모하므로 관리가 필요함

안전한 세션 관리 방법

  1. 세션 ID 추측 방어: 예측 불가능한 값으로 생성해야 함
  2. 세션 고정(Fixation) 방어: 인증 후 새로운 세션 ID를 발급해야 함
  3. 세션 탈취 방어: HttpOnly, Secure 속성 적용
  4. 세션 타임아웃 설정 (application.properties)
  5. server.servlet.session.timeout=30m
  6. 다중 로그인 방어 (SecurityConfiguration.java)
  7. http.sessionManagement(auth -> auth .sessionFixation(ses -> ses.newSession()) .maximumSessions(1) .maxSessionsPreventsLogin(true));

3. JWT (JSON Web Token)

JWT는 서버에서 클라이언트의 인증 상태를 유지하기 위해 사용하는 토큰 기반 인증 방식이다. JWT는 쿠키나 세션과 달리 서버에서 상태를 저장하지 않고도 인증을 유지할 수 있다(Stateless).

 

jwt 토큰은 https://jwt.io/ 에서 내용을 뜯어볼 수도 있다.

 

JWT 구조 JWT는 Header.Payload.Signature의 3가지 부분으로 구성된다.

  • Header: 알고리즘과 타입 정보 포함
  • Payload: 사용자 정보(클레임, Claim) 포함
  • Signature: 변조 방지 및 보안 강화

JWT 클레임(Claim) 종류

  • iss: 토큰 발급자
  • sub: 토큰 제목
  • exp: 만료 시간
  • iat: 발급 시간
  • aud: 대상자 정보

3.1. JWT 생성

JWT는 사용자가 로그인할 때 생성되며, 이후 요청에서 Authorization 헤더를 통해 서버로 전달된다.

 

JWT 생성 과정

  1. 사용자가 로그인하면 서버에서 JWT를 생성한다.
  2. 클라이언트는 JWT를 로컬 스토리지나 세션 스토리지에 저장한다.
  3. 이후 요청 시 Authorization 헤더에 JWT를 포함하여 서버에 전송한다.
String jwtToken = Jwts.builder()
    .claim("name", userEntity.getName())
    .claim("email", userEntity.getEmail())
    .subject(userEntity.getUsername())
    .id(String.valueOf(userEntity.getSeq()))
    .issuedAt(new Date())
    .expiration(new Date(System.currentTimeMillis() + 86400000))
    .signWith(secretKey, Jwts.SIG.HS256)
    .compact();

3.2. JWT 검증

JWT가 유효한지 확인하려면 서명(Signature)을 검증하고 만료 시간을 체크해야 한다.

public boolean validateToken(String token, UserEntity userEntity) {
    if (isTokenExpired(token)) {
        return false;
    }
    return getSubjectFromToken(token).equals(userEntity.getUsername());
}

3.3. JWT 필터 적용

서버는 클라이언트가 전송한 JWT를 검증하는 필터를 사용하여 보안 기능을 강화한다.

@Component
public class JwtRequestFilter extends OncePerRequestFilter {
    @Autowired
    private JwtUtils jwtUtils;
    @Autowired
    private UserRepository userRepository;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);
            String subject = jwtUtils.getSubjectFromToken(token);
            UserEntity userEntity = userRepository.findByUsername(subject);
            if (!jwtUtils.validateToken(token, userEntity)) {
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                return;
            }
        }
        filterChain.doFilter(request, response);
    }
}

4. Spring Security 설정

Spring Security를 활용하여 JWT 기반 인증을 적용할 수 있다.

 

JWT를 사용하는 SecurityConfiguration 설정

@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
    @Autowired
    private JwtRequestFilter jwtRequestFilter;

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(auth -> auth
            .requestMatchers("/login", "/register").permitAll()
            .anyRequest().authenticated()
        );
        http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }
}

5. 마무리

이번 강의를 통해 쿠키, 세션, JWT 기반 인증 방식의 차이점Spring Security에서 JWT를 활용하는 방법을 학습했다.

특히 Stateless 인증 방식인 JWT를 활용하여 확장성과 보안성을 높이는 방법을 이해했다.

 

Spring Security는 이 전에 프로젝트를 해오면서 여러번 다뤄본 프레임워크지만 보안과 직결된만큼 구조가 복잡하다. 완벽히 이해하려면 더 많이 뜯어보고 연습해야 하는 것 같다.

 


이 글은 LG CNS AM Inspire Camp 1기 진행 중 Obsidian에 정리해뒀던 글을 블로그에 옮긴 글입니다.