0+ 스프링/0+ 스프링 Security

[스프링 시큐리티] 4. 기본 API 및 Filter 이해(동시 세션 제어/세션 고정 보호/세션 정책)

힘들면힘을내는쿼카 2023. 1. 2. 21:23
728x90
반응형

[스프링 시큐리티] 4. 기본 API 및 Filter 이해(동시 세션 제어/세션 고정 보호/세션 정책)

해당 포스팅은 인프런에서 스프링 시큐리티 정수원님의 강의를 참고하여 작성했습니다.
스프링 시큐리티 - Spring Boot 기반으로 개발하는 Spring Security - 인프런 | 강의

 

스프링 시큐리티 - Spring Boot 기반으로 개발하는 Spring Security - 인프런 | 강의

초급에서 중.고급에 이르기까지 스프링 시큐리티의 기본 개념부터 API 사용법과 내부 아키텍처를 학습하게 되고 이를 바탕으로 실전 프로젝트를 완성해 나감으로써 스프링 시큐리티의 인증과

www.inflearn.com

동시 세션 제어

우리가 사용하는 웹서비스 중에 동일한 계정으로 동시에 로그인하는 것을 허용하지 않는 경우가 있습니다.(일반적으로 유료 강의를 제공하는 사이트가 허용하지 않죠.)
이러한 것을 중복 로그인을 허용하지 않는 것이라고 말하는데, 어떻게 중복으로 로그인 했는지 알까요?
동시 세션 제어를 통해서 중복 로그인을 방지할 수 있습니다.
그렇다면 스프링 시큐리티는 어떻게 이를 처리 할까요?

동시 세션 제어 과정

  • 동일한 계정으로 인증을 받을때 생성되는 세션의 허용 갯수를 유지하거나 만료시키는 정책을 의미 합니다.

정책은 2가지가 있습니다.
2가지 정책 모두 동일한 계정을 사용하고, 최대 세션 허용 갯수를 초과했다고 가정 합니다.

  • 이전 사용자 세션 만료
  • 현재 사용자 인증 실패

이전 사용자 세션 만료

  • maxSessionsPreventsLogin(false)

MySecurityConfig

현재 사용자 인증 실패 정책을 코드로 표현하면 다음과 같습니다.

@Configuration
@EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
            http
                .authorizeRequests()
                .anyRequest().authenticated();

            http
                .formLogin();

            http
                .sessionManagement() // 세션 관리 기능이 작동
                //.invalidSessionUrl("/invalid") // 세션이 유효하지 않을 때 이동할 페이지
                .maximumSessions(1) // 최대 허용 가능 세션 수
                .maxSessionsPreventsLogin(false) // true: 동시 로그인 차단, false: 기존 세션 만료
                //.expiredUrl("/expired"); // 세션이 만료된 경우 이동 할 페이지
    }
}

MySecurityController

@Slf4j
@RestController
public class MySecurityController {

    @GetMapping("/")
    public String index(HttpSession session) {
        return "home";
    }
}

2개의 웹브라우저를 띄우고 테스트를 해보면 다음과 같습니다.

  • 첫번째 브라우저에서 로그인을 합니다.

 

  • 두번째 브라우저에서 로그인을 시도합니다.

 

  • 첫번째 브라우저에서 새로고침을 눌러봅니다.
    • 로그아웃된 것을 확인 할 수 있습니다.

현재 사용자 인증 실패

  • maxSessionsPreventsLogin(true)

MySecurityConfig

현재 사용자 인증 실패 정책을 코드로 표현하면 다음과 같습니다.

@Configuration
@EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
            http
                .authorizeRequests()
                .anyRequest().authenticated();

            http
                .formLogin();

            http
                .sessionManagement() // 세션 관리 기능이 작동
                //.invalidSessionUrl("/invalid") // 세션이 유효하지 않을 때 이동할 페이지
                .maximumSessions(1) // 최대 허용 가능 세션 수
                .maxSessionsPreventsLogin(true) // true: 동시 로그인 차단, false: 기존 세션 만료
                //.expiredUrl("/expired"); // 세션이 만료된 경우 이동 할 페이지
    }
}

2개의 웹브라우저를 띄우고 테스트를 해보면 다음과 같습니다.

  • 첫번째 웹브라우저를 통해서 로그인을 시도 합니다.

 

  • 두 번째 브라우저를 통해 로그인을 시도합니다.

 

  • 로그인에 실패 합니다.

세션 고정 보호

세션 공격은 공격자가 먼저 세션 ID를 받은 후, 세션 ID를 사용자에게 심어두어 사용자가 그 세션 ID로 인증하도록 유도하는 방법 입니다.

이러한 세션 공격을 막기 위해서 세션 고정 보호가 생겼습니다.
인증 할 때마다 새로운 세션과 쿠키를 생성하여 공격자가 사용자의 세션 ID를 공유할 수 없게 만드는 것 입니다.

세션 공격 과정

MySecurityConfig

@Configuration
@EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

            http
                .authorizeRequests()
                .anyRequest().authenticated();

            http
                .formLogin();

            http
                .sessionManagement()
                .sessionFixation().none();
                // changeSessionId(): 세션 아이디 변경(default),
                // none(): 세션 고정 보호 미설정,
                // migrateSession(): 서블릿 3.1 이하에서 changeSessionId() 작동하도록,
                // newSession(): 새로운 세션 생성
    }
}

세션 공격 시뮬레이션

  • 공격자가 웹 어플리케이션에 접속 합니다.
    • JSESSIONID를 발급 받은 것을 확인 합니다.

 

 

  • 공격자가 발급받은 JSESSIONID를 복사하여 사용자의 JSESSIONID로 붙여넣습니다.

 

  • 로그인을 시도 합니다.
    • 로그인이 완료되면 localhost:8080/으로 이동합니다.

 

 

  • 공격자가 localhost:8080/에 접속합니다.
    • 공격자가 로그인을 하지 않고 서버의 자원을 이용 할수 있습니다..!!!

MySecurityConfig

세션 공격을 방지하기 위해서
로그인할때 마다 JSESSIONID를 변경 합니다.
이 방법을 세션 고정 보호라고 합니다.

@Configuration
@EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

            http
                .authorizeRequests()
                .anyRequest().authenticated();

            http
                .formLogin();

            http
                .sessionManagement()
                .sessionFixation().changeSession();
                // changeSessionId(): 세션 아이디 변경(default),
                // none(): 세션 고정 보호 미설정,
                // migrateSession(): 서블릿 3.1 이하에서 changeSessionId() 작동하도록,
                // newSession(): 새로운 세션 생성
    }
}

 

  • 공격자가 웹어플리케이션에 접속하여 JSESSIONID를 발급받습니다.

 

  • 공격자의 JSESSIONID을 복사하여 사용자의 JSESSIONID에 붙여 넣습니다.

 

  • 사용자가 로그인을 합니다.
    • JSESSIONID가 변경된 것을 확인 할 수 있습니다.

 

  • 공격자가 심어 놓은 JSESSIONID가 변경되었기 때문에 사용자의 인증 정보로 서버의 자원에 접근 할수 없습니다.
728x90

세션 정책

  • SessionCreationPolicy.IF_REQUIRED
    • 스프링 시큐리티가 필요시 세션 생성(default)
  • SessionCreationPolicy.ALWAYS
    • 스프링 시큐리티가 항상 세션 생성
  • SessionCreationPolicy.NEVER
    • 스프링 시큐리티가 생성하지 않지만 이미 존재하면 사용
  • SessionCreationPolicy.STATELESS
    • 스프링 시큐리티가 생성하지 않고 존재해도 사용하지 않음(JWT)
@Configuration
@EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

            http
                .authorizeRequests()
                .anyRequest().authenticated();

            http
                .formLogin();

            http
        .sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
          /**
             * SessionCreationPolicy.IF_REQUIRED    : 스프링 시큐리티가 필요시 세션 생성 (default)
             * SessionCreationPolicy.ALWAYS         : 스프링 시큐리티가 항상 세션 생성
             * SessionCreationPolicy.NEVER          : 스프링 시큐리티가 생성하지 않지만 이미 존재하면 사용
             * SessionCreationPolicy.STATELESS      : 스프링 시큐리티가 생성하지 않고 존재해도 사용하지 않음 (JWT)
 */


    }
}

 

정리

 

 

 

 

728x90
반응형