세션 관리

enxnong·2024년 6월 15일
0

스프링 시큐리티

목록 보기
4/13

정수원님의 강의 스프링 시큐리티 완전 정복 [6.x 개정판] 보면서 공부한 내용입니다.

동시 세션 제어

sessionManagement().maximumSessions()

  • 사용자(하나의 계정)가 동시에 여러 세션을 생성하는 것을 관리하는 전략이다
  • 사용자 인증 후 활성화된 세션의 수가 설정된 maximumSessions 값과 비교하여 제어 여부를 결정한다

💡 Session 이란?

  1. Session의 배경 : 클라이언트와 서버가 있는 경우, 클라이언트는 서버에 요청하고 서버는 클라이언트의 응답을 받는다. 클라이언트가 접속을 하면 connect이 생기면서 클라이언트의 정보를 저장한다. 하지만 서버는 클라이언트를 식별할 수 있는 아이디나 값이 없다. 그리고 connect이 계속 유지되는 것이 아니라 http프로토콜은 연결을 끊어버려서 disconnect로 만든다.
    만약 최초 요청 후 또 한 번 요청을 했을 때 서버는 클라이언트를 식별할 수 있는 값이 없기 때문에 새로운 클라이언트로 인식을 하게 된다. 즉, 서버는 같은 클라이언트가 요청했을 때 가지고 있는 정보를 활용할 수 있는 방법이 없는 것이다.
  1. Session의 활용 : 클라이언트가 최초 요청 후에 재요청 할 때 클라이언트에 이름을 쿠키형태로 발급한다. (Session ID) 클라이언트마다 고유한 ID가 생기므로 클라이언트가 재요창할 때 해당하는 ID에 담긴 정보를 가지고 활용할 수 있게 된다.

동시 세션 제어 2가지 유형

  • 사용자 세션 강제 만료 (maximumSessions : 1)
    • 동일한 사용자가 첫 번째 로그인 후 두번째 로그인 할 때 세션의 수는 2개 생성됨
    • 이후 첫번째 사용자가 다시 로그인 할 때 maximumSessions은 1개이므로 로그인한지 오래된 사용자의 세션을 강제 만료시킴
    • 즉, 최대 허용 개수만큼 동시 인증이 가능하고 그 외 이전 사용자의 세션을 만료시킨다

  • 사용자 인증 시도 차단 (maximumSessions : 1)

    • 동일한 사용자가 첫 번째 로그인 후 두번째 로그인 할 때 세션의 수는 2개 생성됨
    • 하지만 세션의 수는 1개가 최대 이므로 두번째 로그인 사용자는 인증 자체가 안된다
    • 즉, 치대 허용 개수만큼 동시 인증 가능하고 그 외 사용자의 인증 시도를 차단한다

sessionManagement() API

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        http
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/invalidSessionUrl","/expiredUrl").permitAll()
                        .anyRequest().authenticated())
                .formLogin(Customizer.withDefaults())
                .sessionManagement(session -> session
                        .invalidSessionUrl("/invalidSessionUrl")
                        // 이미 만료된 세션으로 요청을 하는 사용자를 특정 엔드포인트로 리다이렉션 할 Url 을 지정
                        // => maxSessionsPreventsLogin(false)인 경우에만 사용가능
                        // => expiredUrl 보다 우선 적용된다     
                        .maximumSessions(1)  // 동시 세션 허용 최대 개수 (필수)
                        .maxSessionsPreventsLogin(true)
                        // false(기본값)인 경우 : 인증하는 사용자에게 접근을 허용하고 기존 사용자의 세션은 만료됨
                        // => 사용자 세션 강제 만료 방법
                        // true인 경우 : 최대 세션 수에 도달했을 때 사용자의 인증을 방지한다
                        // => 사용자 인증 시도 차단 방법
                        .expiredUrl("/expiredUrl")
                        // 세션을 만료하고 나서 리다이렉션 할 URL 을 지정한다 
						// => maxSessionsPreventsLogin(false)인 경우에만 사용가능
                );

        return http.build();
    }

세션 고정 보호

sessionManagement().sessionFixation()

  • 사용자가 로그인 할 때 새로운 세션을 생성하거나 세션 ID를 변경함으로써 세션 고정 공격에 자동으로 대응한다

💡 세션 고정 공격이란?
공격자가 악의적으로 사이트에 접근하여 세션을 생성한 후 다른 사용자가 같은 세션으로 로그인하도록 유도해서 사용자의 모든 권한 및 정보를 공격자가 볼 수 있도록 하는 것

sessionManagement() API

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 http.sessionManagement((session) -> session
 .sessionFixation(sessionFixation -> sessionFixation.newSession())
 // sessionFixation에 들어간 4가지 보호 전략
 // 1. changeSessionId()
 // => 기존 세션을 유지하면서 세션 ID(공격자의 쿠키인 세션ID)만 변경하여 인증 과정에서 세션 고정 공격을 방지하는 방식 (기본값)
 // 2. newSession()
 // => 새로운 세션을 생성하고 기존 세션 데이터를 날려버리는 방식
 // 단, SPRING_SECURITY_로 시작하는 속성은 복사하여 사용한다
 // 3. migrateSession()
 // => 새로운 세션을 생성하고 모든 기존 세션 속성을 새 세션으로 복사하는 방식
 // 4. none()
 // => 기존 세션을 그대로 사용하는 방식
 // => 세션 고정 공격을 방어하지 않는 방식 (절대 사용 X)
 );
 return http.build();

세션 생성 정책

sessionManagement().sessionCreationPolicy()

  • 인증된 사용자에 대한 세션 생성 정책을 설정하여 어떻게 세션을 관리할지 경정할 수 있으며 이 정책은 SessionCreationPolicy로 설정된다

세션 생성 정책 전략

  1. SessionCreationPolicy. ALWAYS
    • 인증 여부에 상관없이 항상 세션을 생성한다
    • 익명 사용자일 때 활용할 수 있다
    • 내부적으로 스프링 시큐리티는 ForceEagerSessionCreationFilter 클래스를 추가 구성하여 세션을 강제로 생성시킨다
    • ForceEagerSessionCreationFilter 이후 계속 생성된 세션 객체를 얻을 수 있다
  2. SessionCreationPolicy. NEVER
    • 스프링 시큐리티가 세션을 생성하지 않지만 스프링 시큐리티 외의 애플리케이션(ex: WAS)이 이미 생성한 세션은 사용할 수 있다
  3. SessionCreationPolicy. IF_REQUIRED (기본값)
    • 필요한 경우에만 세션을 생성한다.
    • ex: 인증이 필요한 자원에 접근할 때 세션을 생성한다
  4. SessionCreationPolicy. STATELESS
    • 세션을 전혀 생성하거나 사용하지 않는다
    • 인증 필터는 인증 완료 후 SecurityContext 를 세션에 저장하지 않으며 JWT(토큰기반의 인증방식)와 같이 세션을 사용하지 않는 방식으로 인증을 관리할 때 유용할 수 있다
    • SecurityContextHolderFilter 는 세션 단위가 아닌 요청 단위로 항상 새로운 SecurityContext 객체를 생성하므로 컨텍스트 영속성이 유지되지 않는다

sessionManagement() API

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        http
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/login").permitAll()
                        .anyRequest().authenticated())
                .formLogin(Customizer.withDefaults())
                .sessionManagement(session -> session
                        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
 // STATELESS 설정에서도 세션이 생성될 수 있다
 // => CSRF 기능이 활성화되어있고 수행된다면 사용자의 세션을 생성하여 CSRF 토큰을 저장하게 된다
 // => SecurityContext 영속성에 영향을 미치지 않는다
                );

        return http.build();
    }

SessionManagementFilter

  • 요청이 시작된 이후 사용자가 인증했는지 감지하고, 인증된 경우에는 세션 고정 보호 메커니즘을 활성화하거나 동시 다중 로그인을 확인하는 등 세션 관련 활동을 수행하기 위해 설정된 세션 인증 전략을 호출하는 필터 클래스
  • 기본적으로 설정되어있지 않아 세션관리 API를 설정하여 생성할 수 있다

  • ChangeSessionId AuthenticationStrategy : 세션 고정 보호
  • ConcurrentSessionControl AuthenticationStrategy : 세션 만료 / 인증 차단
  • RegisterSession AuthenticationStrategy : 세션에 저장된 정보를 관리
  • SessionFixation ProtectionStrategy : ChangeSessionId AuthenticationStrategy와 ChangeSessionId AuthenticationStrategy가 세션 고정 보호를 위해 존재함

ConcurrentSessionFilter

  • 사용자의 세션이 만료로 표시되었는지 확인하고 만료로 표시된 경우 로그아웃 처리를 수행한다(세션 무효화)

    즉, ConcurrentSessionFilter는 세션을 만료할 사용자를 찾아서 동시 세션 제어를 유지시키기 위해 만료 설정이 true인 사용자를 만료 처리한다

  • 각 요청에 대해 SessionRegistry.refreshLastRequest(String)를 호출하여 등록된 세션들이 항상 최신의 상태로 유지하도록 업데이트 해준다

    마지막 업데이트 날짜와 시간을 가지도록 한다

흐름

  1. 사용자가 인증 요청을 한다
  2. SessionManagementFilter에서 세션 허용 개수를 확인하고 초과하면 세션 만료를 설정한다
  3. 이후 사용자가 인증 성공 후 재접속할 때 ConcurrentSessionFilter가 정보를 받는다
  4. 사용자의 세션이 만료되었는지 확인 후 만료가 된 경우(true)라면 실제로 사용자의 세션을 만료하기 위해 로그아웃 처리를 한다 (실제 만료가 된 상태로 만든다)
  5. 사용자의 세션이 만료되었는지 확인 후 만료가 된 경우(false)라면 최신 상태로 업데이트 한다
profile
높은 곳을 향해서

0개의 댓글