본문 바로가기

Spring/Security

Spring Security 3: SecurityFilter #2

DefaultLoginPageGeneratingFilter

  • 로그인페이지 연결해주는 필터
  • 스프링 시큐리티를 적용했을 때 자동으로 생성되는 로그인 페이지

AuthenticationProcessingFilter

인증 과정

1. 사용자가 인증 요청을 보내면 AuthenticationProcessingFilter를 거친다.

2. 인증 필터에서는 검증되지 않은 Authentication 객체를 생성해서 AuthenticationManager에 전달한다.

3. AuthenticationManager는 인증은 검증하고 인증된 정보(인가 등)을 다시 반환하고 사용자의 인증 과정이 완료된다.

큰 흐름은 위 순서로 진행되며 앞서 작성한 객체들은 모두 인터페이스로 작성되어 있으며 알맞은 구현체에서 작업을 수행한다.

 

구현체(번외)

AuthenticationProcessingFilter는 추상클래스로 대표적으로 UsernamePasswordAuthenticationFilter 구현체가 있고
해당 구현체를 통해 인증되지 않은 Authentication 객체를 생성한다.

Authentication의 구현체로는 대표적으로UsernamePasswordAuthenticationToken이 있다.(일반적인 http 요청 시 생성)

 

생성된 Authentication 객체는 AuthenticationManager로 전달된다.

AuthenticationManager는 사용자 인증을 위한 API를 제공하는 인터페이스다
기본 구현체로 ProviderManager가 있고 ProviderManager의 내부에는 List 형식의 여러 Provider가 있는데 Authentication 타입에 따라 호출되는 구현체가 다르다.

예를 들어 UsernamePasswordAuthenticationToken 타입의 Authentication은 DaoAuthenticationProvider가
처리한다.

 

여기서 잠깐!
-> 사용자가 할 수 있는 요청은 한개인데 왜 List로 만들었을까??
-> 서버의 구현에 따라 기본적인 아이디/비번 형태, OAuth 도는 SSO, LDAP 등 여러가지 인증 정책이 있다.
각 요청마다 적당한 정책으로 매핑하는 것보다 List를 갖고 순회하며 요청을 처리하는 방법이 더 효율적이기 때문에
리스트로 갖는다.

RememberMeAuthenticationFilter

  1. RememberMe 인증 쿠키 감지 (Remember Me 쿠키를 찾는다)
  2. 쿠키가 존재한다면 RememberMeService 호출

-> RememberMe 서비스의 구현체에는 TokenBasedRememberMeServices, PersistentTokenBasedRememberMeServices가 있는데
각각 다음의 역할

  • TokenBasedRememberMeServices — MD5 해시 알고리즘 기반 쿠키 검증
  • PersistentTokenBasedRememberMeServices — 외부 데이터베이스에서 인증에 필요한 데이터를 가져오고 검증함
  1. RememberMeService에서 쿠키 값을 사용하여 유효한 사용자인지 검사하고 유효항 경우 RememerMeAuthenticationToken 발급(앞서 이야기한 Authentication 객체의 구현체 중 하나이다. 다른 구현체로 UsernamePasswordAuthenticationToken가 존재)

-> 뒷 부분은 일반 로그인에서 생성되는 Authentication 타입인 UsernamePasswordAuthenticationToken 이후 동작
과정과 동일

 

아래와 같이 필터체인에 추가 가능

 

.rememberMe((rememberMe) -> rememberMe
                        .key("my-remember-me")
                        .rememberMeParameter("remember-me")//html 로그인 페이지에 name에 해당하는 파라미터 값
                        .tokenValiditySeconds(300))// 쿠키 기반

 

SecurityContextPersistenceFilter

 

SecurityContextRepository 인터페이스 구현체를 통해 사용자의 SecurityContext를 가져오거나 갱신 인증 관련 필터 중 가장 최상단에 위치 - 이미 인증된 사용자는 다시 로그인할 필요 없다.
SecurityContext가 존재하지 않는다면, empty SecurityContext를 생성함

SecurityContextRepository의 기본적인 구현체는 HttpSessionSecurityContextRepository을 사용

 

SecurityContext가 존재하지 않을 때에도 무조건적으로 SecurityContext를 생성하고 저장한다는 비효율로 인해 성능상 이슈가 발생해서 해당 필터는 deprecated 되고 SecurityContextHolderFilter로 대체됐다. 

 

앞서 설명한 내용과 동일하지만 SecurityContext를 load 하고 읽기만 수행다는 점이 차이점이다.

관련 링크(https://docs.spring.io/spring-security/reference/servlet/authentication/persistence.html#securitycontextholderfilter)

SessionManagementFilter

  • 세션 고정 보호
    session-fixation attack — 세션 하이재킹 기법중 하나로 정상 사용자의 세션을 탈취하여 인증을 우회하는 기법

사용자가 로그인 할 때, 인증받기 전 세션과 인증받은 후의 세션이 같음을 이용해서 세션을 탈취함

즉, 인증 전에 사용자가 가지고 있던 세션이 인증 후에는 사용되지 않도록 하면 해당 공격에 효과적으로 대응할 수 있음

  • Spring Security에서는 4가지 설정 가능한 옵션을 제공함
    • none — 아무것도 하지 않음 (세션을 그대로 유지함)
    • newSession — 새로운 세션을 만들고, 기존 데이터는 복제하지 않음
    • migrateSession — 새로운 세션을 만들고, 데이터를 모두 복제함
    • changeSession — 새로운 세션을 만들지 않지만, session-fixation 공격을 방어함 (단, servlet 3.1 이상에서만 지원)

AbstractAuthenticationProcessingFilter 객체는 SessionManagementFilter와 동일한 세션 전략을 수행한다.
내부를 보면 SessionAuthenticationStrategy를 공유하는 것을 알 수 있다.


즉, 인증 후 세션을 어떻게 관리할지에 대한 전략과 세션을 설정하는 필터에서 선택하는 전략을 동일하게 해서 일관성을 지케가 한다는 의미

 

코드는 아래와 같다.

 

.sessionManagement((sessionManagement -> sessionManagement
                        .sessionFixation().changeSessionId() // session fixation 방지
                        .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) // 세션 생성 전략
                        .invalidSessionUrl("/") // 유효하지 않은 세션에서 요청시 리다이렉트 되는 url
                        .maximumSessions(1) // 1개의 로그인만 가능
                        .maxSessionsPreventsLogin(false) // 새로운 로그인 발생시 기존 로그인이 아닌 새로운 로그인 허용
                ));