Skip to content

iq-dev-lab/spring-security-deep-dive

Repository files navigation

🔐 Spring Security Deep Dive

"HTTP 요청이 Filter Chain을 통과해 인증·인가되는 전체 여정"


"@PreAuthorize를 쓰는 것과, FilterChainProxy가 15개 Filter를 어떤 순서로 거쳐 인증을 결정하는지 아는 것은 다르다"

FilterChainProxy.doFilter() 한 줄씩 분석부터 AuthenticationManager → ProviderManager → UserDetailsService 전체 체인,
JWT 토큰이 SecurityContext에 저장되는 과정, OAuth2 Authorization Code Flow의 모든 단계까지
왜 이렇게 설계됐는가 라는 질문으로 Spring Security 내부를 끝까지 파헤칩니다


GitHub Java Spring Security Docs License


🎯 이 레포에 대하여

Spring Security에 관한 자료는 넘쳐납니다. 하지만 대부분은 "어떻게 설정하나" 에서 멈춥니다.

일반 자료 이 레포
"@PreAuthorize("hasRole('ADMIN')")를 붙이면 권한 검사가 됩니다" FilterSecurityInterceptorAccessDecisionManager를 통해 GrantedAuthority 목록과 ConfigAttribute를 비교하는 Voter 체인 전 과정
"JWT 필터를 만들어 Security Config에 등록하세요" UsernamePasswordAuthenticationFilter 앞에 커스텀 JwtAuthenticationFilter를 추가했을 때 SecurityContextHolderAuthentication이 저장되는 정확한 시점과 ExceptionTranslationFilter가 그 뒤를 받는 방식
"UserDetailsService를 구현하면 됩니다" DaoAuthenticationProviderUserDetailsService.loadUserByUsername()을 호출한 뒤 PasswordEncoder.matches()로 검증하고 UsernamePasswordAuthenticationToken을 생성해 SecurityContext에 저장하는 내부 코드
"OAuth2 로그인은 oauth2Login()으로 설정하세요" OAuth2LoginAuthenticationFilter가 Authorization Code를 받아 Token Endpoint를 호출하고 OAuth2UserSecurityContext에 저장하기까지의 OAuth2AuthorizationCodeAuthenticationProvider 전 과정
"CSRF 토큰을 헤더에 담아야 합니다" CsrfFilterCsrfTokenRepository에서 토큰을 로드하고 X-CSRF-TOKEN 헤더와 비교하는 시점, SameSite 쿠키 정책과의 관계
이론 나열 실행 가능한 코드 + Spring Security 소스코드 직접 추적 + Postman/curl 인증 실험 + @WithMockUser 검증

🚀 빠른 시작

각 챕터의 첫 문서부터 바로 학습을 시작하세요!

Architecture Authentication Authorization Session JWT OAuth2 Advanced


📚 전체 학습 지도

💡 각 섹션을 클릭하면 상세 문서 목록이 펼쳐집니다


🔹 Chapter 1: Security Architecture

핵심 질문: HTTP 요청이 들어왔을 때 FilterChainProxy는 15개 Filter를 정확히 어떤 순서로 실행하는가?

DelegatingFilterProxy부터 SecurityContext 생명주기까지 완전 분해 (7개 문서)
문서 다루는 내용
01. DelegatingFilterProxy와 FilterChainProxy 관계 Servlet Container가 관리하는 DelegatingFilterProxy와 Spring이 관리하는 FilterChainProxy의 책임 분리, springSecurityFilterChain Bean이 등록되는 시점
02. SecurityFilterChain 구성과 우선순위 여러 SecurityFilterChain이 등록될 때 RequestMatcher로 체인을 선택하는 과정, @OrdersecurityMatcher()의 상호작용
03. Security Filter 15개 완전 정복 DisableEncodeUrlFilter부터 FilterSecurityInterceptor까지 모든 Filter의 실행 순서·역할·건너뛸 수 있는 조건, FilterOrderRegistration에서 순서를 결정하는 방식
04. SecurityContext & SecurityContextHolder ThreadLocal 기반 SecurityContextHolder가 요청 스레드에 Authentication을 저장하고 정리하는 생명주기, MODE_INHERITABLETHREADLOCAL 전략과 비동기 환경 함정
05. Authentication 객체 구조 Principal, Credentials, Authorities의 역할 분리, UsernamePasswordAuthenticationToken이 인증 전·후에 다른 필드를 갖는 이유, isAuthenticated() 플래그 의미
06. GrantedAuthority vs Role 차이 ROLE_ 접두사 규칙의 기원, hasRole()hasAuthority()가 내부적으로 다르게 처리되는 방식, RoleHierarchy로 계층적 권한을 설정하는 메커니즘
07. SecurityContextPersistenceFilter 동작 요청 시작 시 HttpSession에서 SecurityContext를 복원하고 응답 후 저장하는 흐름, SecurityContextRepository의 역할, Stateless JWT 환경에서 이 Filter를 비활성화해야 하는 이유

🔹 Chapter 2: Authentication Process

핵심 질문: 폼 로그인 요청이 들어왔을 때 AuthenticationManager는 어떤 경로로 사용자를 인증하는가?

AuthenticationManager부터 Custom Provider 작성까지 (7개 문서)
문서 다루는 내용
01. AuthenticationManager vs ProviderManager 차이 AuthenticationManager 인터페이스와 ProviderManager 구현체의 관계, 부모 ProviderManager로 위임하는 계층 구조, 전역 vs 로컬 AuthenticationManager 분리 전략
02. AuthenticationProvider 체인 동작 ProviderManager가 등록된 Provider를 순서대로 supports()로 확인하는 과정, DaoAuthenticationProvider·AnonymousAuthenticationProvider 등 기본 Provider 목록
03. UserDetailsService 구현과 커스터마이징 UserDetailsService.loadUserByUsername()의 계약, UserDetails 인터페이스의 각 필드(isAccountNonExpired, isEnabled 등)가 인증 흐름에 미치는 영향, 캐싱 전략
04. PasswordEncoder 종류와 선택 BCryptPasswordEncoder·Argon2PasswordEncoder·SCryptPasswordEncoder 비교, DelegatingPasswordEncoder로 여러 인코더를 혼용하는 마이그레이션 전략, 인코딩 업그레이드
05. UsernamePasswordAuthenticationFilter 분석 폼 로그인 요청이 들어올 때 attemptAuthentication()successfulAuthentication() / unsuccessfulAuthentication() 흐름, AuthenticationSuccessHandler가 호출되는 정확한 시점
06. Remember-Me 인증 메커니즘 토큰 기반(TokenBasedRememberMeServices)과 영속 토큰 기반(PersistentTokenBasedRememberMeServices) 전략 비교, RememberMeAuthenticationFilter 실행 조건
07. Custom Authentication Provider 작성 AuthenticationProvider 구현으로 SMS OTP·API Key 인증 추가, supports() 메서드로 처리 가능한 토큰 타입을 선언하는 방식, AuthenticationManagerBuilder에 등록하는 방법

🔹 Chapter 3: Authorization & Method Security

핵심 질문: @PreAuthorize가 붙은 메서드는 어떻게 AOP Proxy를 통해 권한 검사를 수행하는가?

@PreAuthorize 동작 원리부터 Custom Authorization Logic까지 (6개 문서)
문서 다루는 내용
01. @PreAuthorize vs @Secured vs @RolesAllowed 세 어노테이션의 SpEL 지원 여부·처리 클래스 차이, @EnableMethodSecurity@EnableGlobalMethodSecurity(deprecated) 전환 시 달라지는 동작
02. Method Security 동작 원리 (AOP Proxy) AuthorizationManagerBeforeMethodInterceptor가 AOP Proxy를 통해 메서드 호출 전에 인터셉트하는 과정, MethodSecurityExpressionHandler가 SpEL 컨텍스트를 초기화하는 방식
03. FilterSecurityInterceptor 내부 구조 URL 기반 접근 제어를 처리하는 FilterSecurityInterceptorSecurityMetadataSource에서 ConfigAttribute를 로드하고 AccessDecisionManager를 호출하는 전 과정
04. AccessDecisionManager와 Voter 체인 AffirmativeBased·ConsensusBased·UnanimousBased 전략 비교, RoleVoter·WebExpressionVoter·AuthenticatedVoter가 각각 ACCESS_GRANTED를 반환하는 조건
05. SpEL을 활용한 복잡한 권한 검사 @PreAuthorize("@permissionEvaluator.check(#id, authentication)") 패턴, PermissionEvaluator 커스터마이징으로 도메인 객체 기반 권한 검사 구현
06. Custom Authorization Logic AuthorizationManager<MethodInvocation> 구현으로 어노테이션 없이 동적 권한 검사, SecurityContextHolder 없이 AuthorizationDecision을 반환하는 함수형 스타일

🔹 Chapter 4: Session Management

핵심 질문: Session Fixation 공격이란 무엇이며, Spring Security는 이를 어떻게 자동으로 방어하는가?

Session 보안 공격 방어부터 CSRF Protection까지 (6개 문서)
문서 다루는 내용
01. Session Fixation 공격과 방어 공격자가 미리 발급한 Session ID를 피해자에게 심는 공격 메커니즘, Spring Security가 인증 성공 후 changeSessionId() 또는 새 세션을 생성해 방어하는 정확한 시점
02. Concurrent Session Control (동시 로그인 제한) maximumSessions(1) 설정 시 SessionAuthenticationStrategy가 기존 세션을 만료시키는 방식, ConcurrentSessionFilter가 만료된 세션 요청을 처리하는 흐름
03. Session Timeout 처리 server.servlet.session.timeout 설정과 SessionManagementFilter의 관계, 세션 만료 후 InvalidSessionStrategy가 호출되는 조건, InvalidSessionUrl 설정
04. SessionRegistry 활용 SessionRegistry로 현재 로그인한 사용자 목록 조회, 관리자가 특정 사용자의 세션을 강제 종료하는 구현, SessionInformation.expireNow()의 동작 방식
05. Stateless Session (JWT 환경) SessionCreationPolicy.STATELESS 설정이 SecurityContextRepositorySessionManagementFilter에 미치는 영향, 세션 없이 매 요청마다 SecurityContext를 재구성하는 과정
06. CSRF Protection 메커니즘 CsrfFilter가 동기화 토큰 패턴으로 요청 위조를 방어하는 원리, CookieCsrfTokenRepository vs HttpSessionCsrfTokenRepository 차이, REST API에서 CSRF를 비활성화해도 안전한 조건

🔹 Chapter 5: JWT Authentication

핵심 질문: Custom JWT Filter는 어떻게 토큰을 검증하고 SecurityContextAuthentication을 저장하는가?

JWT 구조 분석부터 Refresh Token Rotation까지 (7개 문서)
문서 다루는 내용
01. JWT 구조 완전 분석 (Header, Payload, Signature) Base64URL 인코딩된 세 파트의 역할, alg·typ 헤더 필드가 검증 알고리즘 선택에 미치는 영향, iss·sub·exp·iat 표준 클레임의 의미와 검증 순서
02. Custom JWT Authentication Filter 작성 OncePerRequestFilter를 상속해 Authorization: Bearer 헤더를 추출하는 구현, UsernamePasswordAuthenticationFilter 앞에 배치해야 하는 이유, shouldNotFilter() 패턴
03. JWT Token 발급 과정 (JwtTokenProvider) io.jsonwebtoken 라이브러리로 토큰을 서명하는 과정, secretKey 관리 전략 (환경 변수·@Value), ClaimsuserId·roles 커스텀 클레임을 추가하는 방법
04. JWT Token 검증과 SecurityContext 저장 JwtParser.parseClaimsJws()가 서명·만료 시간을 검증하는 내부 과정, 검증 성공 후 Authentication 객체를 생성해 SecurityContextHolder에 저장하는 정확한 코드 경로
05. Refresh Token 전략 (RTR — Refresh Token Rotation) Access Token 만료 시 Refresh Token으로 재발급하는 흐름, RTR 전략에서 이전 Refresh Token을 무효화해 탈취 감지하는 방법, Redis 기반 Refresh Token 저장소 구현
06. Claims 추출과 사용 Filter 이후 Controller에서 @AuthenticationPrincipal로 커스텀 UserDetails를 주입받는 패턴, JwtAuthenticationToken.getPrincipal()에서 Claims를 꺼내 사용하는 방법
07. JWT Token 만료 및 갱신 처리 ExpiredJwtException이 Filter에서 발생했을 때 ExceptionTranslationFilter를 거치지 않고 직접 401 응답을 보내야 하는 이유, 만료 5분 전 Silent Refresh 클라이언트 전략

🔹 Chapter 6: OAuth2 & OpenID Connect

핵심 질문: "카카오로 로그인" 버튼을 눌렀을 때 OAuth2LoginAuthenticationFilter는 내부적으로 어떤 일을 하는가?

OAuth2 Grant Type 분석부터 Resource Server 구현까지 (7개 문서)
문서 다루는 내용
01. OAuth2 4가지 Grant Type Authorization Code·Implicit·Resource Owner Password·Client Credentials 각 Grant Type의 사용 시나리오, PKCE 확장이 Authorization Code Flow를 강화하는 방법
02. Authorization Code Flow 완전 분석 /oauth2/authorization/{registrationId} 요청부터 Authorization Code 수신, Token Endpoint 호출, 사용자 정보 로드까지의 10단계 전 과정, state 파라미터가 CSRF를 방지하는 방식
03. OAuth2LoginAuthenticationFilter 동작 OAuth2AuthorizationCodeAuthenticationProvider가 Authorization Code를 Access Token으로 교환하는 과정, OAuth2UserService를 호출해 OAuth2User를 로드하는 흐름
04. ClientRegistration과 InMemoryClientRegistrationRepository ClientRegistration의 각 필드(clientId, redirectUri, scopes, authorizationGrantType)가 실제 HTTP 요청에서 어떻게 사용되는가, Google·Kakao 설정 비교
05. OAuth2AuthorizedClient 관리 OAuth2AuthorizedClientRepository가 Access Token을 세션에 저장하는 방식, @RegisteredOAuth2AuthorizedClient로 Controller에서 토큰을 주입받는 패턴, 토큰 자동 갱신
06. Custom OAuth2UserService 작성 DefaultOAuth2UserService를 확장해 소셜 계정을 DB 사용자와 연결하는 구현, 첫 로그인 시 회원가입 처리, OAuth2UserUserDetails를 통합하는 패턴
07. JWT Bearer Token Resource Server @EnableResourceServer(deprecated) 대신 oauth2ResourceServer(jwt()) DSL 설정, JwtDecoder가 JWK Set URI에서 공개키를 가져와 서명을 검증하는 과정, scope 기반 권한 매핑

🔹 Chapter 7: Advanced Security Topics

핵심 질문: 실무에서 자주 마주치는 CORS, Security Headers, 멀티 테넌시 보안 이슈를 어떻게 올바르게 구성하는가?

CORS 설정부터 Multi-tenancy Security까지 (5개 문서)
문서 다루는 내용
01. CORS Configuration (CorsFilter vs @CrossOrigin) CorsFilter@CrossOrigin이 처리되는 필터 체인 위치 차이, Preflight 요청(OPTIONS)이 인증 필터를 통과해야 하는 이유, CorsConfigurationSource 빈 등록 방식
02. Security Headers (CSP, HSTS, X-Frame-Options) HeadersConfigurer가 자동으로 추가하는 헤더 목록, Content-Security-Policy로 XSS를 방어하는 디렉티브 구성, HSTS max-ageincludeSubDomains 설정이 적용되는 조건
03. Security Events & Listeners AuthenticationSuccessEvent·AuthenticationFailureBadCredentialsEvent·AuthorizationDeniedEventApplicationListener로 처리하는 패턴, 로그인 실패 횟수 제한 구현
04. Method Security with SpEL 고급 활용 @PostFilter·@PreFilter로 컬렉션 반환값·파라미터를 필터링하는 방식, returnObject·filterObject 내장 변수, 커스텀 SecurityExpressionRoot로 도메인 특화 SpEL 함수 추가
05. Multi-tenancy Security 전략 테넌트별 SecurityFilterChain 분리 전략, TenantContextHolderSecurityContextHolder 연계, Row-Level Security와 @PreAuthorize를 결합한 데이터 격리 패턴

🗺️ 목적별 학습 경로

🟢 "Spring Security가 마법처럼 느껴진다" — 핵심 흐름 파악 (1주)
Day 1  Ch1-01  DelegatingFilterProxy와 FilterChainProxy 관계
Day 2  Ch1-03  Security Filter 15개 완전 정복
Day 3  Ch1-04  SecurityContext & SecurityContextHolder ← 핵심
Day 4  Ch2-01  AuthenticationManager vs ProviderManager
Day 5  Ch2-03  UserDetailsService 구현과 커스터마이징
Day 6  Ch3-01  @PreAuthorize vs @Secured vs @RolesAllowed
Day 7  Ch4-06  CSRF Protection 메커니즘
🔵 "JWT 인증을 구현했지만 원리를 모른다" — JWT 완전 정복 (1주)
Day 1  Ch1-04  SecurityContext & SecurityContextHolder
Day 2  Ch1-07  SecurityContextPersistenceFilter 동작
Day 3  Ch4-05  Stateless Session (JWT 환경)
Day 4  Ch5-01  JWT 구조 완전 분석
Day 5  Ch5-02  Custom JWT Authentication Filter 작성
Day 6  Ch5-04  JWT Token 검증과 SecurityContext 저장
Day 7  Ch5-05  Refresh Token 전략 (RTR)
🟣 "OAuth2 Authorization Code Flow를 설명하지 못한다" — OAuth2 정복 (1주)
Day 1  Ch6-01  OAuth2 4가지 Grant Type
Day 2  Ch6-02  Authorization Code Flow 완전 분석 ← 핵심
Day 3  Ch6-03  OAuth2LoginAuthenticationFilter 동작
Day 4  Ch6-04  ClientRegistration 구성
Day 5  Ch6-05  OAuth2AuthorizedClient 관리
Day 6  Ch6-06  Custom OAuth2UserService 작성
Day 7  Ch6-07  JWT Bearer Token Resource Server
🔴 "Spring Security 소스코드를 직접 읽고 내부를 완전히 이해하고 싶다" — 전체 정복 (7주)
1주차  Chapter 1 전체 — Security Architecture 완전 분해
        → FilterChainProxy.doFilterInternal()에 브레이크포인트를 걸고 15개 Filter 스택 트레이스 확인

2주차  Chapter 2 전체 — Authentication Process 내부
        → DaoAuthenticationProvider.retrieveUser()에서 UserDetailsService 호출 시점 직접 추적

3주차  Chapter 3 전체 — Authorization & Method Security
        → @PreAuthorize가 붙은 메서드 호출 시 AOP Proxy가 개입하는 지점 디버거로 확인

4주차  Chapter 4 전체 — Session Management
        → SessionFixationProtectionStrategy.onAuthentication() 소스 직접 읽기

5주차  Chapter 5 전체 — JWT Authentication
        → JwtAuthenticationFilter에서 SecurityContext에 저장되는 과정을 curl 실험으로 검증

6주차  Chapter 6 전체 — OAuth2 & OpenID Connect
        → OAuth2LoginAuthenticationFilter 소스로 Authorization Code → Access Token 교환 과정 추적

7주차  Chapter 7 전체 — Advanced Topics
        → CorsFilter와 @CrossOrigin이 동시에 설정됐을 때 충돌 시나리오 MockMvc로 재현

📖 각 문서 구성 방식

모든 문서는 동일한 구조로 작성됩니다.

섹션 설명
🎯 핵심 질문 이 문서를 읽고 나면 답할 수 있는 질문
🔍 왜 이 보안 메커니즘이 필요한가 공격 시나리오와 보안 설계 배경
😱 흔한 보안 실수 Before — 취약한 코드와 그 결과
올바른 보안 구현 After — 안전한 코드와 원리 설명
🔬 내부 동작 원리 Spring Security 소스코드 직접 추적 + ASCII 구조도
💻 실험으로 확인하기 Postman/curl + @WithMockUser + 디버거 브레이크포인트
🔒 보안 체크리스트 이 메커니즘을 도입할 때 반드시 확인할 항목
⚖️ 트레이드오프 이 설계의 장단점, 언제 다른 방법을 택할 것인가
📌 핵심 정리 한 화면 요약
🤔 생각해볼 문제 개념을 더 깊이 이해하기 위한 질문 + 해설

🔬 핵심 분석 대상 — FilterChainProxy 요청 흐름

이 레포의 모든 챕터는 아래 Filter 실행 흐름을 완전히 이해하는 것을 목표로 합니다.

// FilterChainProxy.doFilterInternal() — 실행되는 Filter 목록 (순서)
//
// ① Ch1-07 SecurityContextHolderFilter          HTTP Session에서 SecurityContext 복원
// ② Ch7-01 CorsFilter                           CORS Preflight 처리  (순서 700)
//    Ch4-06 CsrfFilter                          CSRF 토큰 검증       (순서 800)
// ③ Ch2-05 UsernamePasswordAuthenticationFilter 폼 로그인 처리
//          JwtAuthenticationFilter (Custom)     JWT 검증 → SecurityContext 저장  ← Ch5
//          BasicAuthenticationFilter            Basic Auth 처리
//          BearerTokenAuthenticationFilter      OAuth2 Resource Server          ← Ch6-07
// ④        RequestCacheAwareFilter              이전 요청 복원
//          SecurityContextHolderAwareRequestFilter
// ⑤        AnonymousAuthenticationFilter        인증 없는 요청에 익명 Authentication 부여
// ⑥ Ch4-01 SessionManagementFilter             세션 고정 방어, 동시 접속 제어
// ⑦        ExceptionTranslationFilter           AuthenticationException → 401 (로그인 리다이렉트)
//                                               AccessDeniedException    → 익명 사용자: 401 / 인증된 사용자: 403
// ⑧ Ch3-03 AuthorizationFilter                 URL 기반 권한 검사 (최종 관문)
//
//
// 인증 성공 후 흐름:
// JwtAuthenticationFilter
//   → JwtTokenProvider.validateToken()        서명 + 만료 시간 검증
//   → JwtTokenProvider.getAuthentication()    Claims → UsernamePasswordAuthenticationToken
//   → SecurityContextHolder.setContext()      ThreadLocal에 저장
//   → FilterChain.doFilter()                  다음 Filter로 진행
//   → DispatcherServlet → Controller

🔗 선행 학습 레포지토리

레포 주요 내용 연관 챕터
spring-core-deep-dive IoC 컨테이너, DI, AOP, Bean 생명주기, Proxy Ch3(Method Security AOP Proxy), Ch7(Multi-tenancy)
spring-mvc-deep-dive DispatcherServlet, Filter vs Interceptor, ArgumentResolver Ch1(DelegatingFilterProxy — Servlet Filter 이해 필수), Ch5(JWT Custom Filter 배치)
spring-boot-internals Auto-configuration, SecurityAutoConfiguration Ch1(SecurityFilterChain 자동 등록 과정)
spring-data-transaction JPA, 트랜잭션 Ch2(UserDetailsService DB 조회), Ch5(Refresh Token Redis 저장)

💡 선행 필수: Spring Core의 AOP / Proxy 개념(Ch3 Method Security), Spring MVC의 Servlet Filter 개념(Ch1 FilterChain)이 반드시 필요합니다.
나머지 챕터는 독립적으로 학습 가능합니다.


🛡️ OWASP Top 10 연계

각 챕터가 방어하는 OWASP 위협 목록입니다.

OWASP 위협 관련 챕터
A01 Broken Access Control Ch3 Authorization, Ch7 Multi-tenancy
A02 Cryptographic Failures Ch5 JWT 서명, Ch2 PasswordEncoder
A03 Injection Ch3 SpEL 안전한 사용
A05 Security Misconfiguration Ch1 Filter 순서, Ch7 Security Headers
A07 Identification and Authentication Failures Ch2 Authentication, Ch4 Session
A08 Software and Data Integrity Failures Ch5 JWT 검증, Ch6 OAuth2 state
A09 Security Logging and Monitoring Failures Ch7 Security Events

A04(Insecure Design), A06(Vulnerable Components), A10(SSRF)은 이 레포의 범위 밖입니다.


🙏 Reference


⭐️ 도움이 되셨다면 Star를 눌러주세요!

Made with ❤️ by Dev Book Lab


"@PreAuthorize를 쓰는 것과, FilterChainProxy가 15개 Filter를 어떤 순서로 거쳐 인증을 결정하는지 아는 것은 다르다"

About

@PreAuthorize를 쓰는 것과, FilterChainProxy가 어떻게 인증을 결정하는지 아는 것은 다르다

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors