[Spring Security] Spring Security

2025. 11. 17. 18:04Spring Security

이 글에서는 Spring Security에 대한 개요 및 주요 구성과 관련 정보에 대해 학습한 내용을 공유합니다.

  • Spring Security
  • 주요 구성 요소
  • 관련 정보
  • 회고

Spring Security

인증/인가 등 보안 전반을 표준화해 애플리케이션을 안전하게 보호하는 스프링 기반 보안 프레임워크

Spring Security는 지속적인 보안 업데이트를 제공하고, 실제 사용되는 검증된 보안 기능을 제공합니다.

개발자는 복잡한 보안 로직을 직접 구현하지 않아도 높은, 수준의 보안 설정이 가능하며 비즈니스 로직에 집중할 수 있습니다.

  • 세션 관리, 암호화, CSRF 방어, CORS 정책 적용, 보안 이벤트 처리 등 실무에서 필요한 공통 보안 기능 내장
  • OAuth2, JWT, LDAP 등 현대화된 보안 방식을 제공합니다.

이 가능하며, 확장성과 호환성이 뛰어납니다.


주요 구성 요소

FilterChain

스프링 시큐리티는 여러 개의 필터를 거치며 모든 요청은 보안 필터를 통과해야 합니다.

요청이 컨트롤러에 도달하기 전 인증/인가/예외 처리를 수행할 수 있도록 합니다.

DelegatingFilterProxy

서블릿 컨테이너의 표준 서블릿 필터로 등록되어 있지만, 보안 로직을 처리하지 않습니다.

서블릿과 스프링 환경의 중간 연결 용도로 FilterChainProxy과 같은 필터에게 위임합니다.

FilterChainProxy

핵심 게이트웨이 필터로, 들어온 요청의 URL에 대해 SecurityFilterChain 적용 여부를 결정하며, SecurityFilterChain의 보안 필터를 순서대로 실행합니다.

SecurityFilterChain의 모든 필터가 통과되어야 비즈니스 로직 수행이 가능하며, 하나라도 통과하지 못한다면 요청은 차단됩니다.

SecurityFilterChain

특정 요청 경로(URL)에 대응하는 보안 필터들의 묶음으로, 상황별로 유연하게 보안 규칙을 지정할 수 있습니다.

  • /login → UserNamePasswordAuthenticationFilter 동작
  • /admin → AuthrizationFilter 동작

AuthenticationManager

요청자가 제출한 인증 정보(아이디, 비밀번호)를 AuthenticationProvider에 전달해 결과를 받아 Authentication 객체를 반환합니다.

Authentication

인증 성공 시 생성되는 결과 객체로, 아래와 같은 정보가 저장되며 애플리케이션 어디서든 사용자의 신원 확인 시 사용됩니다.

  • 사용자명(username)
  • 비밀번호(credential)
  • 권한 목록(authorities)
  • 인증 여부(authenticated flag)

ProviderManager

Spring Security의 AuthenticationManager 기본 구현체로, 여러 개의 AuthenticationProvider를 순회하며 인증을 시도합니다.

ex) 폼 로그인 시도 → 실패 시 LDAP 시도 → 실패 시 OAuth2 시도…

AuthenticationProvider

구체적인 인증 방법을 정의하는 모듈입니다.

ex) DaoAuthenticationProvider는 DB기반 사용자 조회(UserDetailService)와 비밀번호 검증(PasswordEncoder)을 처리하며, 필요 시 커스텀 Provider를 만들어 다른 인증 방식을 추가할 수 있습니다.

UserDetails / UserDetailsService

Spring Security가 사용자 정보를 표준화된 방식으로 읽기 위해 제공하는 인터페이스입니다.

DB에서 엔티티 조회 후 UserDetails로 변환 & 반환하면 인증 절차에 활용될 수 있습니다.

@Service
@RequiredArgsConstructor
public class CustomUserDetailsService implements UserDetailsService {

    private final UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        // 1. email로 DB에서 사용자 조회
				User user = userRepository.findByEmail(email)
                .orElseThrow(() -> new UsernameNotFoundException(email));

        // 2. 사용자 Entity에 저장된 문자열 형식의 권한으로 SimpleGrantedAuthority 생성
        String roleName = user.getUserRole().name();
        SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_" + roleName);
        
        // 3. UserDetails 생성 및 반환
        return org.springframework.security.core.userdetails.User
                .withUsername(user.getEmail())
                .password(user.getPassword())
                .authorities(authority)
                .build();
    }
}

GrantedAuthority

사용자가 가진 권한을 표현하는 인터페이스로 인가(Authorization)에 사용됩니다.

ex) ROLE_ADMIN, ROLE_USER, READ_PRIVATE

SimpleGrantedAuthority

GrantedAuthority의 단순 구현체로, 문자열 한 줄(ex: “ROLE_ADMIN”)만으로 권한을 표현할 수 있으며, 가장 흔히 사용되는 형태입니다.

new SimpleGrantedAuthority("ROLE_" + roleName);

SecurityContextHolder

현재 실행 중인 스레드에 연결된 SecurityContext를 저장/관리합니다.

각 스레드마다 할당 된 개인 저장소인 ThreadLocal에 Authentication 객체를 보관해두었다가, 애플리케이션 어디서든 현재 로그인한(인증된) 사용자를 확인할 수 있습니다.

요청이 끝나면 ThreadLocal은 자동으로 비워지며, 다른 요청의 정보와 독립적으로 처리가능하다.

AuthorizationFilter

인증이 끝난 사용자에 대해 인가를 검증하기 위한 필터입니다.

URL 매핑이나 어노테이션(@PreAuthorize) 기반 규칙을 평가합니다.

AuthorizationManager

인가 로직의 실제 판단을 수행하는 핵심 컴포넌트입니다.

ExceptionTranslationFilter

인승 실패 또는 거부와 같은 보안 예외를 적절히 처리하는 필터입니다.

로그인 페이지로 리다이렉트하거나, JSON 에러 응답을 반환해 일관된 처리를 보장합니다.


관련 정보

HTPP의 Stateless 특성

상태가 없다는 것은 서버가 클라이언트의 이전 요청을 기억하지 못한다는 것을 의미합니다.

모든 요청을 독립적으로 처리할 수 있지만, 로그인이나 상태유지가 불가능합니다.

stateless의 한계를 극복하고, 클라이언트의 상태를 기억하기 위해 세션, 쿠키, JWT를 활용할 수 있습니다.

인증과 인가

인증은 사용자의 신원을 확인하는 과정이고, 인가는 사용자가 접근 권한을 확인하는 과정입니다.

항상 인증 후 인가가 진행되어야 합니다.

CSRF (Cross-Site Request Forgery)

사이트 간 요청 위조 공격 기법으로, 공격자가 로그인된 사용자의 권한을 도용해 사용자가 의도하지 않은 요청을 서버에 보내도록 만드는 공격입니다.

CORS (Cross-Origin Resource Sharing)

브라우저의 보안정책 동일 출처 정책(Same-origin policy)을 안전하게 허용할 수 있도록 만들어진 메커니즘(정책)입니다.

주로 프론트 서버와 백엔드 서버의 주소가 다를 때, 브라우저는 보안상 이유로 백엔드에 보내는 요청을 차단합니다.

이 때 브라우저가 아닌 백엔드 서버에서 특정 프론트엔드의 요청을 허락하도록 설정하면, 브라우저가 프론트 서버의 백엔드 서버로의 요청을 허용합니다.

Filter vs Interceptor

Filter와 Interceptor는 아래와 같이 동작 시점과 범위의 차이가 존재합니다.

[ Filter ]

  • 동작 시점: 서블릿 컨테이너
  • 동작 범위: 플리케이션으로 들어오는 모든 요청 또는 스프링과 전혀 관련 없는 정적 리소스에 대한 접근 제어

[ Interceptor ]

  • 동작 시점: 디스패처 서블릿 내부, 스프링 MVC 컨택스트 안에서 빈을 주입
  • 동작 범위: 스프링 MVC과 관련한 데이터 활용

보안은 애플리케이션 전체를 보호해야 합니다.

따라서 스프링 시큐리티는 프레임워크에 종속되는 인터셉터 보다, 근본적이고 포괄적인 방어가 가능한 필터를 기반으로 설계되었습니다.


회고

이번 학습을 통해 스프링 시큐리티의 개념과 다양한 구성 요소들을 알아보았다.

특히 프레임워크가 체계적인 보안 구조를 제공해, 개발자는 직접 보안 로직을 구현하지 않아도 높은 수준의 보안을 확보할 수 있다는 점이 인상적이었다.

하지만 이러한 편리한 만큼 프레임워크의 의존성도 커지기 때문에, 단순히 기능을 사용하는 것에서 그칠 것이 아니라 스프링 시큐리티의 내부 동작 원리를 이해 할 필요성을 깨달았다.

따라서 다음 학습 단계에서는 스프링 시큐리티의 필터 체인 기반의 인증/인가 흐름 등 내부 동작 방식에 대해 깊이 있게 공부하고자 한다.