Spring Security 중복 로그인 방지 매커니즘 분석

선종우·2023년 7월 25일
0

1.분석 환경

  • 중복 로그인을 방지하고자 sessionManagement()설정을 해주었다.
@Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
        http.csrf().disable().cors().disable()
                .authorizeRequests(request -> request
                        .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
                        .dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll()
                        .mvcMatchers("/images/**",  "/events/**", "/members/**", "/lorahost/**", "/sneat/**", "/img/**", "/club/**").permitAll()
                        .mvcMatchers("/admin/**").hasRole("ADMIN")
                        .anyRequest().authenticated()
                ).formLogin(login -> login
                        .loginPage("/members/login")
                        .usernameParameter("email")
                        .passwordParameter("password")
                        .failureUrl("/")
                        //.successHandler(loginSuccessHandler)
                        //.defaultSuccessUrl("/events", true) defaultSuccessUrl설정되면 loginsuccessHandler 작동 안 함
                        .permitAll()
                ).logout(logout -> logout
                        .logoutSuccessUrl("/"))
                .sessionManagement()
                	.maximumSessions(1)
                	.maxSessionsPreventsLogin(false);

        return http.build();

    }
  • 위 설정에 따라 등록된 필터 리스트는 아래와 같다.
    1. DisableEncodeUrlFilter
    2. WebAsyncManagerIntegrationFilter
    3. SecurityContextPersistenceFilter
    4. HeaderWriterFilter
    5. LogoutFilter
    6. UsernamePasswordAuthenticationFilter
    7. ConcurrentSessionFilter
    8. RequestCacheAwareFilter
    9. SecurityContextHolderAwareRequestFilter
    10. AnonymousAuthenticationFilter
    11. SessionManagementFilter
    12. ExeptionTranslationFilter
    13. FilterSecurityInterceptor

2. 흐름 분석

  1. 사용자 로그인 시 UsernamePasswordAuthenticationFilter 내 로그인 로직 수행 이중 OnAuthentication메소드 내에 특정 Principal(Id)에 대한 session정보를 모두 불러온 후 허용된 session 개수와 비교하는 부분이 있음

  2. 허용 가능한 session 개수를 초과한 경우 allowableSessionsExceeded()를 호출함

    여기서 세션의 전부 expired처리를 함 분석 당시 메모리에 아래와 같은 session정보들이 있었는데 전부 expired된 상태

"BC35C96D6FF711B831812CC10071A01A" -> {SessionInformation@18783} 
"4A6A11CAF73103B2C977EDDA3727D5A9" -> {SessionInformation@17545} 
"3F7E23EEA2A96DC1A0DF392D98AB2F7A" -> {SessionInformation@17892} 
"6F5705C42B79BB92A819A6A79D78538D" -> {SessionInformation@17546} 
"C143154293CFF220EC64BCB319104D1D" -> {SessionInformation@17572} 
"A4718C6B925A45B754EB2BF867296D4B" -> {SessionInformation@18574} 
"141BB2B060F9D37862361E8ACC7A5520" -> {SessionInformation@17812} 
  1. 그 다음 새로운 세션을 SessionRegistry에 등록하는데, SessionRegistry 구현체인 SessionRegistyImpl에는 {Pricipal : SessionId set}으로된 ConcurrentMap이 있음(getAllSessions()가 반환하는 값이 여기에 있는 SessionId Set을 이용함) 또한 {SessionId : SessionInfo}로 구성된 sessionIds Map이 있음. 여기서 신규 로그인한 사용자의 session을 Pricipal에 등록함

  2. 만약 이전에 로그인했던 사용자가 다시 사이트에 접근하면 ConcurrentSessionFilter에서는 해당 session 계정에 대한 logout처리를 진행하고 추가 filter을 진행하지 않고 반환함

0개의 댓글