본문 바로가기

공부내용 정리/스프링

스프링 시큐리티 정리 내용

스프링 시큐리티는 스프링 기반 애플리케이션의 보안(인증과 권한, 인가 등)을 담당하는 스프링의 하위 프레임워크이다.

스프링시큐리티는 '인증'과 '권한'에 대한 부분을 Filter 흐름에 따라 처리한다.

스프링 시큐리티에서는 주로 서블릿 필터(filter)와 이들로 구성된 필터체인으로의 구성된 위임모델을 사용하고 보안과 관련해서 체계적으로 많은 옵션을 제공해주기때문에 개발자 입장에서는 일일이 보안관련 로직을 작성하지 않아도 된다는 장점이 있다.

서블릿필터는 사용자의 요청을 가로채서 전처리하거나 서버의 응답을 가로채서 후처리할 수 있다.

유연한 설계로 다양한 확장 및 커스터마이징 가능

비즈니스 로직과 인증,권한 로직을 분리가능

필터들이 애플리케이션에 대한 모든 요청을 감싸서 처리한다.

[용어정리]

접근주체(Principal) : 보호된 리소스에 접근하는 대상

인증(Authentication) : 보호된 리소스에 접근한 대상에 대해 누구인지 확인하는 과정

인가(Authorize) : 해당 리소스에 대한 접근 가능한 권한을 가지고 있는지 확인하는 과정

권한 : 어떤 리소스에 대한 접근 제한, 모든 리소스는 접근 제어 권한이 걸려 있음.

비밀번호(Credential)

스프링 시큐리티 특징과 구조

  • 보안과 관련하여 체계적으로 많은 옵션을 제공하여 편리하게 사용할 수 있음
  • Filter 기반으로 동작하여 MVC와 분리하여 관리 및 동작
  • 어노테이션을 통한 간단한 설정
  • Spring Security는 기본적으로 세션&쿠키방식으로 인증

================================================================

[스프링 시큐리티 필터]

[SecurityContextPersistenceFilter]

SecurityContextRepository에서 SecurityContext를 로드하고 저장

[LogoutFilter]

로그아웃 URL로 지정된 가상URL에 대한 요청을 감시하고 매칭되는 요청이 있으면 사용자를 로그아웃시킴

[UsernamePasswordAuthenticationFilter]

사용자명과 비밀번호로 이뤄진 폼기반 인증에 사용하는 가상URL요청을 감시하고 요청이 있으면 사용자의 인증을 진행함

[DefaultLoginPageGeneratingFilter]

폼기반 또는 OpenID기반 인증에 사용하는 가상URL에 대한 요청을 감시하고 로그인 폼 기능을 수행하는데 필요한 HTML을 생성함.

[BasicAuthenticationFilter]

HTTP기본 인증 헤더를 감시하고 이를 처리함

[RequestCacheAwareFilter]

로그인 성공 이후 인증 요청에 의해 가로채어진 사용자의 원래 요청을 재구성하는데 사용

[SecurityContextHolderAwareRequestFilter]

HttpServletRequest를 HttpServletRequestWrapper를 상속하는 하위 클래스(SecurityContextHolderAwareRequestWrapper)로 감싸서 필터 체인상 하단에 위치한 요청 프로세서에 추가 컨텍스트를 제공

[AnonymouseAuthenticationFilter]

이 필터가 호출되는 시점까지 사용자가 아직 인증받지 못했다면 요청관련 인증 토큰에서 사용자가 익명 사용자로 나타나게 됨

[SessionManagementFilter]

인증된 주체를 바탕으로 세션 트래킹을 처리해 단일 주체와 관련한 모든 세션들이 트래킹되도록 도움

[ExceptionTranslationFilter]

이 필터는 보호된 요청을 처리하는 동안 발생할 수 있는 기대한 예외의 기본 라우팅과 위임을 처리

[FilterSecurityInterceptor]

이 필터는 권한부여와 관련한 결정을 AccessDecisionManager에게 위임해 권한부여 결정 및 접근제어 결정을 쉽게 만들어줌.

================================================================

[주요 모듈]

[SecurityContextHolder]

보안주체의 세부 정보를 포함하여 프로그램의 현재 보안 컨텍스트에 대한 세부정보를 저장한다.

[SecurityContext]

Authentication을 보관하는 역할을 하며, SecurityContext를 통해 Authentication객체를 꺼내올 수 있다.

[Authentication]

현재 접근하는 주체의 정보와 권한을 담은 인터페이스이다. Authentication 객체는 Security Context에 저장되며, SecurityContextHolder를 통해 SecurityContext에 접근하고, Security를 통해 Authentication에 접근할 수 있다.

[UsernamePasswordAuthenticationToken]

Authentication을 implements한 AbstractAuthenticationToken의 하위 클래스로, User의 Id가 Principal의 역할을 하고, Password가 Credential의 역할을 한다.

UsernamePasswordAuthenticationToken의 첫번째 생성자는 인증 전의 객체를 생성하고, 두번째 생성자는 인증이 완료된 객체를 생성한다.

[AuthenticationProvider]

실제 인증에 대한 부분을 처리하는데, 인증 전의 Authentication객체를 받아서 인증이 완료된 객체를 반환하는 역할을 한다. AuthenticationProvider 인터페이스를 구현해서 Custom한 AuthenticationProvider를 작성해서 AuthenticationManager에 등록하면 된다.

[Authentication Manager]

인증에 대한 부분은 SpringSecurity의 AuthenticationManager를 통해서 처리하게 되는데, 실질적으로는 AuthenticationManager에 등록된 AuthenticationProvider에 의해 처리된다. 인증이 성공하면 2번째 생성자를 이용해 인증이 성공한 객체를 생성하여 SecurityContext에 저장한다. 그리고 인증상태를 유지하기 위해 세션에 보관하며, 인증이 실패한 경우에는 AuthenticationException을 발생시킨다.

AuthenticationManager를 implements한 ProviderManager는 실제 인증 과정에 대한 로직을 가지고 있는 AuthenticationProvider를 List로 가지고 있으며, ProviderManager는 for문을 통해 모든 provider를 조회하면서 authenticate처리를 한다.

ProviderManager에 직접 구현한 CustromAuthenticationProvider를 등록하는 방법은 WebSecurityConfigurerAdapter를 상속해 만든 SecurityConfig에서 할 수 있다. WebSecurityConfigurerAdapter의 상위 클래스에서는 AuthenticationManager를 가지고 있기때문에 우리가 직접만든 CustomAuthenticationProvider를 등록할 수 있다.

[UserDetails]

인증에 성공하여 생성된 UserDetails 객체는 Authentication객체를 구현한 UsernamePasswordAuthenticationToken을 생성하기 위해 사용된다. UserDetails 인터페이스는 정보를 반환하는 메소드를 가지고 있다. UserDetails인터페이스의 경우 직접개발한 UserVO 모델에 UserDetails를 implements하여 처리하거나 UserDetailsVO에 UserDetails를 implements하여 처리할 수 있다.

[UserDetailsService]

UserDetailsService 인터페이스는 UserDetails 객체를 반환하는 단 하나의 메소드를 가지고 있는데, 일반적으로 이를 구현한 클래스의 내부에 UserRepository를 주입받아 DB와 연결하여 처리한다.

[PasswordEncoding]

AuthenticationManagerBuilder.userDetailsService().passwordEncoding()을 통해 패스워드 암호화에 사용된 PasswordEncoder 구현체를 지정할 수 있다.

[GrantedAuthority]

GrantedAuthority는 현재 사용자(principal)가 가지고 있는 권한을 의미한다. ROLE_ADMIN이나 ROLE_USER와 같이 ROLE_*의 형태로 사용하며, 보통 'roles'라고 한다. GrantedAuthority 객체는 UserDetailsService에 의해 불러올 수 있고, 특정 자원에 대한 권한이 있는지를 검사하여 접근 허용 여부를 결정한다.

================================================================

[스프링 시큐리티 처리과정]

 

  1. 사용자가 아이디,비밀번호로 로그인을 요청
  2. AuthenticationFilter에서 UsernamePasswordAuthenticationToken을 생성하여 AuthenticationManager에게 전달.
  3. AuthenticationManager는 등록된 AuthenticationProvider(s)들을 조회하여 인증을 요구
  4. AuthenticationProvider(s)는 UserDetailsService를 통해 입력받은 아이디에 대한 사용자정보를 DB에서 조회
  5. 입력받은 비밀번호를 암호화여 DB의 비밀번호와 매칭되는 경우 인증이 성공된 UsernameAuthenticationToken을 생성하여 AuthenticationManager로 반환
  6. AuthenticationManager는 UsernameAuthenticationToken을 AuthenticationFilter로 전달
  7. AuthenticationFilter는 전달받은 UsernameAuthenticationToken을 LoginSuccessHandler로 전송하고, SecurityContextHolder에 저장