
| 용어 | 정의 | 예시 |
|---|---|---|
| 인증 (Authentication) | 사용자의 신원 확인 | 로그인 |
| 인가 (Authorization) | 권한 검사 | 관리자 메뉴 접근 |
| CSRF | 인증된 세션을 악용해 위조 요청 | 게시글 삭제 링크 클릭 유도 |
| XSS | 스크립트 삽입으로 쿠키·세션 탈취 | 댓글에 <script> 삽입 |
| 세션 하이재킹 | JSESSIONID 탈취 후 세션 가장 | 공용 Wi-Fi 스니핑 |
Spring 기반 애플리케이션에서 인증·인가 전 과정을 책임지는 보안 프레임워크
[클라이언트 요청]
│
▼
DelegatingFilterProxy (WAS → Spring 관문)
│
▼
FilterChainProxy (URL 매칭 허브)
│
▼
┌─ SecurityFilterChain ──────────────────────────────┐
│ │ │ │
│ │ └─ UsernamePasswordAuthenticationFilter │ 로그인
│ └────── CsrfFilter │ CSRF
└────────── FilterSecurityInterceptor │ 최종 인가
| 포인트 | 설명 |
|---|---|
| 정의 | 서블릿 표준 Filter → 이름으로 Spring Bean을 찾아 위임 |
| 역할 | WAS ↔ Spring Security 필터 체인 관문 |
| 비유 | 건물 1층 안내데스크 — 실제 검문은 각 층의 경비가 수행 |
| 포인트 | 설명 |
|---|---|
| 정의 | 여러 SecurityFilterChain을 저장하고, 요청 URL 패턴에 따라 적절한 체인을 선택 |
| 확장 | 예: /api/** 는 JWT, /admin/** 는 세션 기반 체인 |
| 매커니즘 | 첫 번째로 매칭되는 체인의 필터들을 순서대로 실행함 |
@Bean
public SecurityFilterChain apiChain(HttpSecurity http) throws Exception {
http.securityMatcher("/api/**")
.sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
URL 매칭 + 필터 리스트를 가진 하나의 Bean
먼저 등록된 체인이 먼저 평가됨
| 순서 | 필터 | 역할 |
|---|---|---|
| 1️⃣ | SecurityContextHolderFilter | ThreadLocal에 인증 객체 저장/복원 |
| 2️⃣ | LogoutFilter | 로그아웃 요청 처리 및 세션 종료 |
| 3️⃣ | UsernamePasswordAuthenticationFilter | 로그인 Form 처리 |
| 4️⃣ | BearerTokenAuthenticationFilter | JWT 토큰 추출 및 검증 |
| 5️⃣ | CsrfFilter | CSRF 토큰 검증 |
| 6️⃣ | ExceptionTranslationFilter | 예외 → 401/403 응답 처리 |
| 7️⃣ | FilterSecurityInterceptor | 최종 인가(권한) 판정 |
[POST /login] (username, password)
↓
UsernamePasswordAuthenticationFilter
↓
AuthenticationManager
↓
DaoAuthenticationProvider
↓ ← DB에서 사용자 조회
UserDetailsService ──→ UserDetails 반환
↓
PasswordEncoder로 비밀번호 검증
↓
성공 → Authentication 객체 생성
↓
SecurityContextHolder에 저장
로그인 요청은 필터가 가로채 처리
DB에서 사용자 정보를 조회하고 비밀번호를 검증
인증 성공 시 Authentication 객체가 SecurityContextHolder에 저장됨
@GetMapping("/admin")
@PreAuthorize("hasRole('ADMIN')")
public String adminPage() {
return "관리자 전용 페이지";
}
메서드 호출 전 MethodSecurityInterceptor가 작동함
AccessDecisionManager가 권한(ROLE_ADMIN) 보유 여부를 평가함
통과 시 메서드 실행 / 실패 시 403 Forbidden 응답 발생
Spring Security에서 자주 사용하는 보안 설정 중
CSRF(Cross-Site Request Forgery)와 CORS(Cross-Origin Resource Sharing)는
프론트와 백엔드가 분리된 구조에서는 필수 요소
| 항목 | 설명 | 대응 방법 |
|---|---|---|
| CSRF (Cross-Site Request Forgery) | 사용자가 의도하지 않은 요청을 인증된 세션으로 유도 | CSRF 토큰 발급 및 검증 필터 (CsrfFilter) |
| CORS (Cross-Origin Resource Sharing) | 서로 다른 출처(도메인) 간 요청이 브라우저에 의해 차단됨 | @CrossOrigin, Spring Security 설정에서 허용 가능 |
CSRF는 POST/PUT/DELETE 요청 시 위조 요청을 방지
CORS는 프론트엔드와 백엔드가 다른 도메인일 경우 필요
http
.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
.cors(Customizer.withDefaults())
.headers(headers -> headers
.contentSecurityPolicy("default-src 'self'"))
.exceptionHandling(ex -> ex
.accessDeniedPage("/403"));
| 설정 | 설명 |
|---|---|
csrf | CSRF 토큰을 쿠키 기반으로 설정 (withHttpOnlyFalse()는 JS 접근 허용용) |
cors | 도메인이 다른 경우 허용 설정 (프론트 ↔ 백 통신 허용) |
headers | CSP 등 보안 헤더 설정 (XSS/클릭재킹 방지) |
exceptionHandling | 401/403 등의 인증·인가 실패 시 사용자 정의 페이지로 이동 |
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().permitAll()
)
.formLogin(Customizer.withDefaults())
.build();
}
| 어노테이션 | 설명 |
|---|---|
@EnableWebSecurity | Spring Security 활성화 |
@Configuration | 설정 클래스 등록 |
@PreAuthorize, @Secured | 메서드 단위 권한 인가 처리 |
@WithMockUser | 테스트용 가짜 사용자 주입 (MockMvc 등에서 사용) |
@PreAuthorize("hasRole('ADMIN')") : 메서드 접근 전 권한 검사
@WithMockUser : 단위 테스트 시 인증된 사용자로 가정 가능