세션관리 - 동시 세션 제어
• 동시 세션 제어는 사용자가 동시에 여러 세션을 생성하는 것을 관리하는 전략이다
• 이 전략은 사용자의 인증 후에 활성화된 세션의 수가 설정된 maximumSessions 값과 비교하여 제어 여부를 결정한다
하나의 계정으로 인해 세션이 여러개 생기는것 == 동시적 세션
[각 클라이언트가 동일한 계정으로 인증을 하게되면 각각 다른 세션이 서버에 생성되고
각각 다른 세션ID가 클라이언트에게 반환된다.]
pc,휴대폰,패드 각각 로그인을 하게된다면
3개의 클라이언트가 각각 세션을 가지게 된다.
최대 세션이 만약 1개라면
-> pc에서 로그인하고 난뒤 휴대폰에서 로그인하면 pc에 인증한게 무효화되거나 휴대폰에서 로그인이 안된다.
동시 세션 제어 2 가지 유형
1. 사용자 세션 강제 만료
두번째로 홍길동으로 접속한 클라이언트까지 세션을 만들어주고,
첫번째로 홍길동으로 접속한 클라이언트의 세션은 만료시킨다.
[세션 강제 만료 ]
이 경우에는 두번째로 홍길동으로 로그인이 실패하게 된다. [ 인증 시도를 차단 ]
sessionManagement() API - 동시 세션 제어
세션 만료 후 리다이렉션 전략
maxSessionsPreventsLogin()이
true이면 세션 최대갯수시 사용자 인증 시도 차단
false라면 인증하는 사용자 접근허용하지만 기존 사용자 세션 만료 [ 사용자 강제 세션 만료 ]
maxSessionsPreventsLogin()이 true이면 세션 최대갯수시 사용자 인증 시도 차단이므로
invalidSessionUrl() , expiredUrl()은 의미가없다 -> 어차피 로그인 시도에서 차단되므로
maxSessionsPreventsLogin()이 false일때
invalidSessionUrl() , expiredUrl() 각각 설정되어있고 안되어있고 일때 결과는 위의 표에 나와있다.
테스트
@EnableWebSecurity
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/login").permitAll()
.anyRequest().authenticated())
.formLogin(Customizer.withDefaults())
.sessionManagement(session -> session
.maximumSessions(1)
.maxSessionsPreventsLogin(false) // default 값은 false
);
return http.build();
}
첫번째 클라이언트 , 두번째 클라이언트 로그인하고 난뒤, 첫번째 클라이언트에서 새로고침을 했더니 다음과 같이 세션만료 메시지가 발생한다.
.maxSessionsPreventsLogin(true)
설정을 다음과 같이 바꾼다면
인증시도 조차 차단된다.
아래와 같이 설정한다면
@EnableWebSecurity
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/invalidSSessionUrl","/expiredUrl").permitAll()
.anyRequest().authenticated())
.formLogin(Customizer.withDefaults())
.sessionManagement(session -> session
.invalidSessionUrl("/invalidSessionUrl")
.maximumSessions(1)
.maxSessionsPreventsLogin(false) // default 값은 false
.expiredUrl("/expiredUrl")
);
return http.build();
}
세션 고정 보호
• 세션 고정 공격은 악의적인 공격자가 사이트에 접근하여 세션을 생성한 다음
다른 사용자가 같은 세션으로 로그인하도록 유도하는 위험을 말한다
• 스프링 시큐리티는 사용자가 로그인할 때 새로운 세션을 생성하거나 세션 ID를 변경함으로써
이러한 공격에 자동으로 대응한다
기본적으로 서버는 로그인을 하기전에 세션을 만들어준다.
[ 익명사용자를 위해 , spring security의 기본 동작 방식임, ]
그 세션을 공격자가 사용자에게 심어서 로그인하면 그 세션을 이용하여 사용자 정보,권한등을 탈취하는것인데
로그인 성공시 세션ID를 새로 생성해서 바꿔주기만 하면 해당 공격은 막을 수 있다.
[세션을 새로 만들어도 되지만, 쿠키로 전달하는 세션ID만 바꿔줘도 세션고정 공격은 막을 수 있다.]
인증되지않은 사용자도 세션을 만들어주는 것은
다음과 같은 이유로 자주 사용됩니다:
- 사용자 상태 유지: 사용자가 로그인하지 않은 상태에서도 사이트 내에서 상태를 유지할 필요가 있을 때 세션이 유용합니다. 예를 들어, 사용자가 로그인을 하지 않은 상태에서 쇼핑몰에서 장바구니에 물건을 추가하거나, 특정 설정을 유지해야 할 때 세션이 사용됩니다.
- 보안상의 이유: 서버는 익명 사용자와 상호작용하는 동안도 세션을 통해 보안 컨텍스트를 관리할 수 있습니다. 이는 사용자가 로그인할 때 세션 고정 공격을 방지하기 위해, 로그인 전후 세션 ID를 재생성하는 방식과 연관됩니다.
- 사이트 기능 제공: 세션을 통해 비로그인 사용자에게도 맞춤형 경험(예: 지역에 맞는 콘텐츠 제공)을 제공할 수 있습니다.
Spring Security의 기본 동작 방식 중 하나는 인증되지 않은 사용자가 접근하더라도 세션을 생성하는 것입니다.
즉, 익명 사용자가 웹 애플리케이션에 처음 접근할 때 세션을 생성하는 것이 일반적인 동작입니다.
- 익명 사용자에 대한 세션 생성:
- 사용자가 로그인하지 않은 상태로 웹 애플리케이션에 접근할 때, Spring Security는 기본적으로 세션을 생성하여 익명 사용자를 관리합니다. 이 세션을 통해 익명 사용자의 활동을 추적하고, 로그인을 하기 전에도 상태를 유지할 수 있게 해줍니다.
- 로그인 후 세션 ID 재생성:
- 사용자가 인증(로그인)하면, Spring Security는 세션 고정 보호(Session Fixation Protection)를 기본적으로 제공합니다. 이를 통해 로그인 성공 시 기존 세션 ID를 폐기하고 새로운 세션 ID를 생성하여 세션 고정 공격을 방지합니다.
- 세션 관리 정책:
- Spring Security는 세션을 어떻게 관리할지 설정할 수 있는 다양한 옵션을 제공합니다. 예를 들어, sessionCreationPolicy 설정을 통해 세션을 항상 생성할지, 필요할 때만 생성할지, 또는 절대 생성하지 않을지 결정할 수 있습니다.
- ALWAYS: 세션을 항상 생성
- IF_REQUIRED: 기본값으로, 요청에 세션이 필요하면 생성
- NEVER: Spring Security가 세션을 생성하지 않지만, 기존 세션은 사용할 수 있음
- STATELESS: 세션을 사용하지 않음 (JWT 등 토큰 기반 인증 시 사용)
- Spring Security는 세션을 어떻게 관리할지 설정할 수 있는 다양한 옵션을 제공합니다. 예를 들어, sessionCreationPolicy 설정을 통해 세션을 항상 생성할지, 필요할 때만 생성할지, 또는 절대 생성하지 않을지 결정할 수 있습니다.
sessionManagement() API - 세션 고정 보호
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.sessionManagement((session) -> session
.sessionFixation(sessionFixation -> sessionFixation.newSession())
);
return http.build();
}
세션 고정 보호 전략
• changeSessionId()
기존 세션을 유지하면서 세션 ID만 변경하여 인증 과정에서 세션 고정 공격을 방지하는 방식이다. 기본 값으로 설정되어 있다
• newSession()
새로운 세션을 생성하고 기존 세션 데이터를 복사하지 않는 방식이다(SPRING_SECURITY_ 로 시작하는 속성은 복사한다)
• migrateSession()
새로운 세션을 생성하고 모든 기존 세션 속성을 새 세션으로 복사한다
• none()
기존 세션을 그대로 사용한다
changeSessionId()는 Spring Security 기본설정이다.
세션 생성 정책
스프링 시큐리티에서는 인증된 사용자에 대한 세션 생성 정책을 설정하여
어떻게 세션을 관리할지 결정할 수 있으며 이 정책은 SessionCreationPolicy 로 설정된다
세션 생성 정책 전략
SessionCreationPolicy.ALWAYS
인증 여부에 상관없이 항상 세션을 생성한다
ForceEagerSessionCreationFilter 클래스를 추가 구성하고 세션을 강제로 생성시킨다
SessionCreationPolicy.NEVER
스프링 시큐리티가 세션을 생성하지 않지만 애플리케이션이 이미 생성한 세션은 사용할 수 있다
SessionCreationPolicy.IF_REQUIRED
필요한 경우에만 세션을 생성한다. 예를 들어 인증이 필요한 자원에 접근할 때 세션을 생성한다 [ Spring Security 기본값 ]
SessionCreationPolicy.STATELESS
세션을 전혀 생성하거나 사용하지 않는다
인증 필터는 인증 완료 후 SecurityContext 를 세션에 저장하지 않으며
JWT 와 같이 세션을 사용하지 않는 방식으로 인증을 관리할 때 유용할 수 있다
SecurityContextHolderFilter 는 세션 단위가 아닌 요청 단위로 항상 새로운 SecurityContext 객체를 생성하므로
컨텍스트 영속성이 유지되지 않는다
sessionManagement() API - 세션 생성 정책
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.sessionManagement((session) -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
);
return http.build();
}
STATELESS설정에도 세션이 생성될 수 있다
스프링 시큐리티에서 CSRF 기능이 활성화 되어 있고 CSRF 기능이 수행 될 경우
사용자의 세션을 생성해서 CSRF 토큰을 저장하게 된다
세션은 생성되지만 CSRF 기능을 위해서 사용될 뿐 인증 프로세스의 SecurityContext 영속성에 영향을 미치지는 않는다.
'인프런 > 스프링 시큐리티 완전 정복 [6.x 개정판]' 카테고리의 다른 글
15) 예외처리 - exceptionHandling(), ExceptionTranslationFilter (0) | 2024.10.24 |
---|---|
14) 세션관리 - SessionManagementFilter / ConcurrentSessionFilter (1) | 2024.10.23 |
12)스프링 MVC 로그인 구현 (1) | 2024.10.21 |
11) 인증 상태 영속성 - SecurityContextRepository & SecurityContextHolderFilter (1) | 2024.10.18 |
10) 사용자 상세 서비스 - UserDetailsService , 사용자 상세 -UserDetails (1) | 2024.10.17 |
댓글