본문 바로가기
Spring/Security

[Spring Security] 보안 정책의 설계도, SecurityConfig 핵심 코드 이해

by coding_whale 2026. 5. 6.
반응형

스프링 시큐리티를 이용한 개발에서 SecurityConfig는 애플리케이션의 모든 보안 전략이 결정되는 '커맨드 센터'와 같다.
어떤 문은 열어두고 어떤 문은 잠글지, 그리고 잠긴 문을 열기 위해 어떤 신분증(JWT)을 검사할지가 이곳에서 모두 정의된다.
오늘은 실무에서 가장 빈번하게 사용되는 3가지 핵심 설정 블록을 통해 보안 정책이 결정되는 원리를 깊이 있게 파헤쳐 본다.

 

1. 보안 정책의 핵심: 권한과 무상태성

애플리케이션의 보안은 크게 '누가 들어올 수 있는가(URL 권한)'와 '인증 상태를 어떻게 유지하는가(세션 정책)'로 나뉜다. 이 두 가지 축이 흔들리면 전체 시스템의 보안 신뢰도가 무너진다.

 

2. 핵심 코드 블록 심층 해설

📌 01. URL 권한 정책: 문을 열어줄 곳과 닫을 곳

.authorizeHttpRequests(auth -> auth
    .requestMatchers("/api/auth/**", "/oauth2/**", "/v3/api-docs/**").permitAll()
    .anyRequest().authenticated()
)
  • 무엇을 하는가: 공개 API와 인증이 필요한 API를 명확히 분리한다.
  • 왜 필요한가: 로그인이 안 된 사용자도 로그인 페이지에 접근할 수 있어야 하고, 개발 단계에서 Swagger 문서나 헬스체크 API는 인증 없이 열려있어야 하기 때문이다.
  • 실패 시나리오: 공개해야 할 URL(예: 이메일 중복 체크)이 누락되면, 프론트엔드에서 로그인을 시작하기도 전에 403 Forbidden 에러를 만나며 전체 인증 플로우가 막혀버린다.

 

📌 02. 세션 정책: STATELESS의 선언

.sessionManagement(session ->
    session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
  • 무엇을 하는가: 서버에서 세션을 유지하지 않겠다고 명시한다. 오직 토큰(JWT)으로만 인증하겠다는 의지다.
  • 왜 필요한가: MSA 환경이나 다중 서버 환경에서 서버 간에 세션을 공유하는 비용을 없애고, 확장성을 극대화하기 위해서다.
  • 실패 시나리오: 세션 기반의 잔재(예: 기본 폼 로그인 세션)가 섞여 있으면, 토큰이 만료되었음에도 세션 때문에 인증이 통과되는 등 보안 취약점이 발생하거나 동작을 예측하기 어려워진다.

 

📌 03. 필터 순서 정책: JWT 검문소 설치

http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
  • 무엇을 하는가: 우리가 만든 JwtAuthenticationFilter를 스프링 시큐리티의 기본 로그인 필터보다 앞에 배치한다.
  • 왜 필요한가: 컨트롤러에 진입하기 전에 헤더의 토큰을 읽어 '인증된 사용자'라는 증명(SecurityContext)을 미리 마쳐야 하기 때문이다.
  • 실패 시나리오: 필터 순서가 틀리면, 정작 컨트롤러에서 @CurrentUser를 쓸 때 null이 반환되어 널 참조 에러(NPE)를 마주하게 된다.

 

3. 데이터의 실제 흐름: "추천 API" 요청 예시

우리가 설정한 보안 정책이 실제 요청에서 어떻게 동작하는지 시뮬레이션해보자.

  1. 요청 발생: 사용자가 GET /api/recommendations를 호출하며 헤더에 Bearer token...을 실어 보낸다.
  2. SecurityConfig 판단: 이 URL은 permitAll 목록에 없으므로 authenticated() 대상이다.
  3. JWT 필터 동작: 필터가 가로채서 토큰의 유효성을 검증하고, SecurityContext에 사용자 정보를 주입한다.
  4. 컨트롤러 도착: SecurityContext에 정보가 있으므로 @CurrentUser User user 파라미터에 사용자 객체가 정상적으로 주입되어 비즈니스 로직이 실행된다.

 

4. 실무자를 위한 개선 포인트

보안 정책은 한 번 짜고 끝나는 것이 아니라 지속적으로 관리되어야 한다.

  • URL 관리의 그룹화: 공개 URL이 많아지면 코드가 지저분해진다. String[] PUBLIC_URLS = {...} 와 같이 상수로 분리하여 관리하면 유지보수성이 비약적으로 좋아진다.
  • 보안 정책 테스트 추가: 새로운 API를 만들 때마다 권한 설정이 제대로 되었는지 테스트 코드로 검증해야 한다. 특히 permitAll 대상이 실수로 잠기지 않았는지 확인하는 '회귀 테스트'가 필수적이다.

 

5. 마무리하며

SecurityConfig를 잘 이해하는 것은 단순히 기능을 구현하는 것을 넘어, 서비스의 '입구'를 설계하는 일이다. 오늘 살펴본 세 가지 설정(URL 권한, 세션 정책, 필터 순서)만 정확히 파악해도 대부분의 인증/인가 이슈를 명확하게 디버깅하고 해결하는데 큰 도움이 될 것이다.

반응형