byunyourim / TIL

오늘 공부한 CS 개념을 정리하는 공간입니다.
0 stars 0 forks source link

Spring Security의 동작 #14

Closed byunyourim closed 2 days ago

byunyourim commented 1 week ago

이슈: Spring Security의 동작

배경

목표

세부 내용

  1. Spring security 가 무엇인지, 개념 파악
  2. Spring securty 동작 흐름
  3. 예제

진행 상황

등록일: 2024.11.20


문서화 결과

byunyourim commented 5 days ago

개념

스프링 기반의 애플리케이션의 인증과 권한을 담당하는 프레임워크

필터를 기반으로 동작한다. 필터는 Dispatcher Serevlet으로 가기 전 적용되며 가장 먼저 URL 요청을 받는다.

Interceptor는 Dispather와 Controller 사이에 위치한다.

image

스프링 MVC에서 요청을 가장 먼저 받는 것은 DispaqtcherServlet인데, DispaqtcherServlet이 요청을 받기 전 여러 필터가 존재한다.


Spring Security Filter Chain

image

Spring Security도 인증 및 인가를 처리하기 위해 Filter를 기반으로 동작한다. 이를 위해서 DelegatingFilterProxy와 FilterChainProxy를 사용한다.

DelegatingFilterProxy는 서블릿 컨테이너에 등록된 여러 필터 중 하나로, 요청을 Spring Security로 전달하기 위한 브릿지 역할을 한다. 모든 요청을 Spring 컨텍스트에서 관리되는 FilterChainProxy로 위임한다.

FilterChainProxy는 SecurityFilterChain을 관리하며, 요청 URL 패턴에 따라 적절한 필터 체인을 선택해 실행한다.

Security Filter Chain은 인증, 세션 관리, 인가 등 다양한 보안 작업을 수행하는 여러 필터로 구성되어 있으며, 각 필터는 체인 방식으로 연결되어 순차적으로 요청을 처리한다. Security Filter를 모두 통과한 요청은 DispatcherServlet 또는 다음 필터로 이동한다.

이러한 구조를 통해 Spring Security는 요청을 안전하게 처리하고 애플리케이션으로 전달되도록 보장한다.

byunyourim commented 5 days ago

Security Filter Chain

Spring Security 에서 요청을 처리하는 필터의 순차적인 집합이다. 클라이언트의 http 요청이 서버에 도달할 때 실행되며, 주로 인증 및 권한 부여와 관련된 작업을 수행한다.

image

가장 먼저 초기화가 진행된다.

Spring Security에서는 인증, 인가에 대한 처리를 여러개의 필터를 연쇄적으로 수행한다.

WebSecurityConfigurerAdapter를 구현한 설정 파일의 내용을 기반으로 필터를 생성한다.

이때, 실제 필터를 생성하는 클래스가 HttpSecurity 이다. 설정 파일 별로 필터 목록을 갖게된 후, 필터들은 WebSecurity 클래스에게 전달된다. WebSecurity는 각각 설정 클래스로 부터 필터 목록들을 전달받고, 다시 FilterChainProxy를 생성자의 인자로 전달한다.

따라서, FilterChainProxy는 각각의 설정 클래스 별로 필터 목록을 갖는다.

후에 사용자가 처음 요청을 하면 가장 먼저 DelegatingFilterProxy가 요청을 받는다. 그리고 나서 FilterChainProxy에게 요청을 위임한다.

DelegatingFilterProxy는 서블릿 필터로, 위임할 때는 SpringSecurityFilterChain이라는 이름을 갖는 Bean을 찾는데, 그 Bean이 FilterChainProxy이다.

이렇게 위임 받은 요청을 가지고 있는 필터들에게 순서대로 요청을 맡긴다.
각각의 필터들이 체인으로 연결되어 수행 -> 넘김 -> 수행으로 진행된다.
이때, 수행되는 메서드가 doFilter이다.


image

스프링 시큐리티는 다양한 필터를 기본적으로 제공한다. 이렇게 제공되는 필터를 Security filter chain이라고 한다.

SecurityContextPersistenceFilter

클라이언트가 요청을 보내면 SecurityContextPersistenceFilter가 먼저 실행되어 SecurityContextRepository를 통해 이전의 보안 컨텍스트를 로드한다. 이 컨텍스트는 SecurityContextHolder에 저장되어 현재 스레드에서 사용할 수 있게된다. 저장된 SecurityContext는 현재 사용자의 인증 정보를 포함하며, 그 안에 Authentication객체가 포함된다.

이렇게 연결된 흐름을 통해 Spring Security는 사용자의 인증상태를 관리하고, 보안을 유지한다.

LogoutFilter

로그아웃 요청을 요청하면 세션을 무효화하고, SecurityContext를 삭제한다. LogoutSuccessHandler가 호출되어 로구아웃 후 동작을 정의한다.

UsernamePasswordAuthenticationFilter

ID, passwrod 를 사용하는 실제 Form 기반 유저 인증을 처리한다. 인증 객체를 만들어 Authentication 객체를 만들어 아이디와 패스워드를 저장하고, AuthenticationManager에게 인증 처리를 맡긴다.
성공 시 AuthenticationSuccessHandler, 실패 시 AuthenticationFailureHandler를 호출한다.

DefaultLoginPageGeneratingFilter

기본 로그인 페이지를 생성한다.

BasicAuthenticationFilter

HTTP Basic 인증 헤더를 처리하여 사용자를 인증한다.

ConcurrentSessionFilter

사용자가 동시에 여러 세션을 유지하는 것을 방지, 제한하기 위해 사용된다.
동일한 사용자 계정으로 여러 브라우저, 탭에서 로그인 한 경우, 이전 세션을 무효화하거나, 사용자의 로그인 세션 수를 제한한다. 매 요청마다 사용자의 세션이 만료되었는지 확인하고, session.expireNow 값으로 만료 설정을 구분한다.

RememberMeAuthenticationFilter

세션이 사라지거나 만료되더라도, 쿠키 또는 DB를 사용하여 저장된 토큰 기반으로 인증을 처리한다. remember-me 기능을 활성화하고 인증 받고 세션이 만료되면 실행되는 필터이다.
세션이 만료되거나 무효화되어 세션 안에 있는 SecurityContext내의 인증 객체가 null일 경우 해당 필터가 작동한다. 인증 객체가 null일 경우 현재 사용자가 요청하는 request header에 remember-me cookie 값을 헤더에 저장한 상태로 왔을 때 이 필터가 접속한 사용자 대신 인증 처리를 시도한다.

SessionManageMentFilter

세션 정책(동시 로그인 제한)을 적용한다ㅏ.

ExceptionTranslationFilter

필터 체인 내에서 발생되는 인증, 인가 예외를 처리한다. 인증 실패 시 AccessDeniedException, 인가 실패 시AuthenticationExceptiton을 던진다.

AnonymousAuthenticationFilter

인증되지 않은 사용자에게 익명 인증 객체를 할당한다. 익명 사용자 필터는 이 필터가 호출되는 시점까지, 인증 시도를 하지 않고 권한도 없이 어떤 자원에 바로 접속을 시도하는 경우 실행된다.

SecurityContextHolderAwareRequestFilter

SecurityContext를 통해 인증 객체를 제공하고, 현재 사용자의 권한을 요청과 연결한다.

FilterSecurityInterceptor

최종 필터로, 요청의 리소스에 대해 사용자의 접근 권한을 확인한다. 권한 확인은 AccessDecisionManager와 SecurityMetadataSource 가 담당한다.


Authentication

인증시 아이디와 패스워드를 담고 인증 검증을 위해 사용된다 . 인증 후 최종 인증 결과 (user 객체, 권한정보) 를 담고 SecurityContext 에 저장되어 전역적으로 참조가 가능합니다.  

 SecurityContextHolder

현재 인증 상태를 저장하고 관리하며, 필터나 다른 인증 관련 객체가 이를 참조한다.

 AuthenticationManager

인증 프로세스를 조정하는 핵심 구성 요소로, 요청을 AuthenticationProvider에 전달한다.

 AuthenticationProvider

실제 인증을 처리하며, 사용자 정보를 검증하거나 외부 시스템과 연동하여 인증을 수행한다.

 UserDetailsService

사용자 정보를 로드하는 서비스로. 주로 데이터베이스에서 사용자 정보를 가져온다.

 UserDetails

UserDetailsService에서 반환하는 사용자 객체로, 사용자 이름, 비밀번호, 권한 등의 정보를 포함한다.

 GrantedAuthority

사용자가 가진 권한(예: ROLE_USER, ROLE_ADMIN)을 나타낸다..


Authorization

SessionAuthenticationStrategy 세션 생성/인증 시 세션 관련 정책을 사용한다.

SessionRegistry

활성 사용자와 세션 정보를 추적 및 관리한다.

AccessDecisionManager

요청에 대한 접근 권한을 결정한다. 여러 DecisionVoter를 사용하여 다수결 방식(예: AffirmativeBased)으로 판단한다..

SecurityMetadataSource

요청 URL, HTTP 메서드, 리소스에 대해 필요한 권한을 정의한다..

DecisionVoters

요청에 대해 허용할지, 거부할지, 중립 상태인지 판단한다. 예: RoleVoter는 사용자의 권한이 리소스에 필요한 역할(Role)을 포함하는지 확인한다.

AuthenticationEntryPoint

인증되지 않은 사용자가 접근 시 처리한다

AccessDeniedHandler

권한이 없는 사용자가 리소스에 접근하려 할 때 호출된다.

AffirmativeBased

여러 투표자의 결과를 바탕으로 접근 결정합니다.

RoleVoter

역할 기반으로 접근 권한을 평가한다.


사용 예시

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .addFilterBefore(new CustomFilter(), UsernamePasswordAuthenticationFilter.class) // 사용자 정의 필터 추가
            .authorizeRequests()
                .antMatchers("/public/**").permitAll() // 공개 URL
                .anyRequest().authenticated() // 나머지 요청은 인증 필요
            .and()
            .formLogin() // 폼 로그인 사용
            .loginPage("/login")
            .permitAll()
            .and()
            .logout()
            .permitAll();
    }
}
byunyourim commented 5 days ago

Spring Security 인증 과정

image
  1. 사용자가 로그인 정보 (id, password)를 입력하고 Authentication 요청한다.

  2. AuthenticationFilter는 사용자가 입력한 정보를 받아 UsernamePasswordAuthenticationToken 객체로 생성한다.

  3. UsernamePasswordAuthenticationToken이 AuthenicationManager에 전달된다.

  4. AuthenticationManager는 여러 AuthenticationProvider 중 하나를 선택해 인증과정을 진행한다.

  5. 선택된 AuthenticationProvider는 사용자 정보를 가져오기 위해 UserDetailsService를 호출한다.

    1. support() 메서드를 통해 현재 인증 요청에 대한 지원 여부를 확인한다. true를 반환하면 AuthenticationProvider가 인증을 처리할 수 있다.
    2. authenticate() 메소드를 통해 DB에 저장된 사용자 정보와 입력한 로그인 정보 비교한다.
    3. UserDetailService의 loadUserByUsername() 을 통해 DB에서 사용자의 정보를 가져온다.
    4. (3)에서 받았던 UsernameAuthenticationToken 객체를 사용하여 사용자가 입력한 로그인 정보를 확인한다.
    5. 입력한 정보와 DB 사용자 정보가 일치하는 경우 Authentication객체를 반환하여 인증이 성공했음을 알린다.
  6. UserDetailsService는 사용자 정보를 포함하는 UserDetails 객체를 반환한다.

  7. AuthenticationProvider는 반환된 UseerDetails를 사용하여 인증을 검증한다.

  8. ProviderManager는 여러 AuthenticationProvider를 관리하고, 해당 프로세스를 구현한다.

  9. 인증이 성공하면 AuthenticationManager는 인증 결과를 반환한다.

  10. 최종적으로 인증 정보가 SecurityContextHolder에 설정되어 애플리케이션의 보안 컨텍스트가 업데이트 된다.

byunyourim commented 5 days ago

SpringSecurity 구성 요소

AuthenticationManager

인증 요청을 처리하는 객체로, 로그인 시 사용자 정보를 확인한다.

UserDetailsService

사용자의 정보를 제공하는 서비스로, loadUserByUsername()메서드를 통해 사용자의 정보(아이디, 비밀번호 등)를 반환한다.

PasswordEncoder

비밀번호를 암호화하는 컴포넌트로 BcryptPasswordEncoder, NoOpPasswordEncoder 등의 구현체가 있다.

SecurityContextHolder

현재 사용자와 관련된 인증 정보를 저장하는 장소로 SecurityContext 객체를 통해 인증된 사용자 정보를 가져올 수 있다.

FilterChain

요청이 처리되는 동안 다양한 보안 필터들을 순차적으로 실행하는 체인

HttpSecurity

HTTP 요청에 대한 보안 구성을 설정하는데 사용된다. URL에 대한 접근 권한을 설정하거나, 세션 관리, CSRF 보호 등을 설정할 수 있다.

GrantedAuthority

사용자가 가지고 있는 권한을 나타내는 객체

SecurityFilterChain

인증, 권한 부여를 위한 필터 체인으로, 각 필터는 요청을 처리하면서 특정 작업을 수행한다.