일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
- dbeaver
- Kubernetes
- MySQL
- intellijIDEA
- Linux
- Spring
- log4j2
- tibero
- JavaScript
- IntelliJ
- Git
- LOG4J
- springboot
- gson
- maven
- nginx
- react
- NCP
- VSCode
- Windows
- BPMN
- JPA
- Java
- database
- useEffect
- gradle
- nodejs
- sapfiorielements
- docker
- mybatis
- Today
- Total
두 손끝의 창조자
Spring Security에서 HttpSecurity와 WebSecurity의 차이점 본문
Spring Security 프레임워크에서 중요한 두 가지 보안 구성 요소인 HttpSecurity와 WebSecurity의 차이점에 대해 자세히 알아보겠습니다. 이번 글에서는 Spring Security 6.4.5 버전을 기준으로 설명하겠습니다.
목차
- Spring Security 6.4.5 개요
- HttpSecurity와 WebSecurity 소개
- HttpSecurity 상세 분석 및 예제
- WebSecurity 상세 분석 및 예제
- 두 구성 요소의 주요 차이점
- 실제 애플리케이션에서의 활용 방법
- 결론
1. Spring Security 6.4.5 개요
Spring Security 6.x는 이전 버전에 비해 상당한 변화가 있었습니다. 특히 Spring Security 6.4.5는 보안 구성을 위한 최신 패러다임을 도입했으며, 람다 기반 구성과, 개선된 타입 안전성을 제공합니다. 이 버전에서는 WebSecurityConfigurerAdapter가 완전히 제거되었고, 컴포넌트 기반 보안 구성이 표준이 되었습니다.
Spring Security 6.4.5는 다음과 같은 주요 변경사항을 포함합니다:
- HttpSecurity 구성을 위한 람다 DSL 확장
- 기본 CSRF 보호 메커니즘 변경
- 요청 매처(matcher) 시스템 개선
- @EnableMethodSecurity 의 도입과 기존 @EnableGlobalMethodSecurity의 대체
- AuthorizationManager 기반의 권한 처리
- WebSecurityCustomizer 대신 더 명시적인 보안 구성 접근법
2. HttpSecurity와 WebSecurity 소개
HttpSecurity
HttpSecurity는 특정 HTTP 요청에 대한 웹 기반 보안을 구성하는 데 사용됩니다. Spring Security 6.4.5에서는 SecurityFilterChain 빈을 통해 HttpSecurity를 구성합니다. 이는 인증, 권한 부여, 로그인 처리, 로그아웃 처리, CSRF 보호, 세션 관리 등과 같은 HTTP 관련 보안을 담당합니다.
WebSecurity
WebSecurity는 FilterChainProxy를 생성하는 데 사용되며, 웹 보안의 전체적인 설정을 구성합니다. Spring Security 6.4.5에서는 WebSecurity의 사용 방식이 변경되었으며, 대부분의 기능이 HttpSecurity로 통합되었습니다. 특히 정적 리소스 처리 방식이 크게 달라졌습니다.
3. HttpSecurity 상세 분석 및 예제
Spring Security 6.4.5에서 HttpSecurity는 HTTP 요청에 대한 보안을 구성하는 핵심 클래스로, 다음과 같은 작업을 수행합니다:
- 인증 메커니즘 구성 (폼 로그인, HTTP 기본 인증, OAuth2 등)
- URL 패턴 기반 접근 제어 설정
- 로그인/로그아웃 처리
- CSRF 보호
- 세션 관리
- 보안 헤더 설정
- 코르스(CORS) 구성
Spring Security 6.4.5의 HttpSecurity 구성 예제
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/", "/home", "/public/**").permitAll()
.requestMatchers("/admin/**").hasAuthority("ADMIN")
.requestMatchers("/user/**").hasAuthority("USER")
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.defaultSuccessUrl("/dashboard")
.permitAll()
)
.logout(logout -> logout
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logout")
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
.permitAll()
)
.csrf(csrf -> csrf.ignoringRequestMatchers("/api/**")) // API 엔드포인트에 대해서만 CSRF 비활성화
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.maximumSessions(1)
.expiredUrl("/login?expired")
)
.headers(headers -> headers
.frameOptions(frameOptions -> frameOptions.sameOrigin())
.contentSecurityPolicy(csp -> csp.policyDirectives("script-src 'self'"))
);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Spring Security 6.4.5에서의 주요 변경점:
- hasRole() 대신 hasAuthority() 사용 권장 (더 명확한 의미 전달)
- .csrf().disable() 대신 .csrf(csrf -> csrf.disable()) 사용
- 메서드 체이닝 대신 람다 기반 구성 사용
- antMatchers(), mvcMatchers() 등이 통합된 requestMatchers() 사용
4. WebSecurity 상세 분석 및 예제
Spring Security 6.4.5에서는 WebSecurity 사용 방식이 크게 변경되었습니다. 이전 버전에서 WebSecurityCustomizer를 통해 주로 사용되던 ignoring() 메서드의 기능이 HttpSecurity로 이전되었습니다.
Spring Security 6.4.5에서의 정적 리소스 처리 방식
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// securityMatcher(): 이 SecurityFilterChain이 적용될 URL 패턴 정의
// 전체 애플리케이션에 이 필터체인을 적용
.securityMatcher("/**")
.authorizeHttpRequests(authorize -> authorize
// requestMatchers(): 특정 URL 패턴에 대한 보안 규칙 정의
// 정적 리소스에 대한 접근 허용
.requestMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**", "/webjars/**", "/favicon.ico").permitAll()
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
.requestMatchers("/actuator/health", "/actuator/info").permitAll()
// 나머지 요청에 대한 권한 설정
.requestMatchers("/public/**").permitAll()
.requestMatchers("/admin/**").hasAuthority("ADMIN")
.anyRequest().authenticated()
)
.formLogin(withDefaults());
return http.build();
}
}
Spring Security 6.4.5에서는 정적 리소스 처리를 위해 이전 버전의 WebSecurity.ignoring() 대신, HttpSecurity의 authorizeHttpRequests() 내에서 permitAll()을 사용하여 처리하는 것이 권장됩니다.
다만, 여전히 특수한 경우에는 아래와 같이 정적 리소스에 대한 보안 필터를 완전히 무시할 수 있습니다:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web
.ignoring()
.requestMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**", "/favicon.ico");
}
// 다른, 정규 애플리케이션 보안 구성을 위한 SecurityFilterChain 빈...
}
그러나 Spring Security 팀은 이 방식보다 HttpSecurity 내에서 permitAll()을 사용할 것을 권장합니다. 이는 보안 측면에서 더 명확하고 일관된 접근 방법을 제공하기 때문입니다.
5. 두 구성 요소의 주요 차이점 및 securityMatcher vs requestMatcher
securityMatcher와 requestMatcher의 차이점
Spring Security 6.4.5에서는 securityMatcher()와 requestMatcher()가 서로 다른 계층과 목적으로 사용됩니다:
securityMatcher()
- 목적: 특정 SecurityFilterChain 빈이 처리할 URL 패턴을 지정합니다.
- 적용 수준: 필터 체인 수준에서 작동하여 어떤 요청이 해당 필터 체인을 통과할지 결정합니다.
- 우선순위: 여러 SecurityFilterChain 빈이 있을 때, 가장 먼저 등록된 빈 중에서 securityMatcher가 일치하는 것이 사용됩니다.
- 사용 사례: API와 웹 페이지 등 서로 다른 보안 구성이 필요한 요청을 분리할 때 사용합니다.
requestMatcher()
- 목적: 이미 선택된 SecurityFilterChain 내에서 특정 URL 패턴에 대한 구체적인 보안 규칙을 정의합니다.
- 적용 수준: authorizeHttpRequests() 메서드 내에서 사용되어 각 URL 패턴에 대한 권한을 지정합니다.
- 우선순위: 먼저 정의된 패턴이 우선적으로 적용됩니다(구체적인 패턴을 먼저 정의해야 함).
- 사용 사례: 정적 리소스, 공개 페이지, 인증이 필요한 페이지 등을 구분할 때 사용합니다.
HttpSecurity와 WebSecurity의 주요 차이점
Spring Security 6.4.5에서 HttpSecurity와 WebSecurity의 주요 차이점은 다음과 같습니다:
특성 HttpSecurity WebSecurity
범위 | HTTP 요청에 대한 보안 | 전역 웹 보안 (제한적 사용) |
주요 기능 | 인증, 권한 부여, 로그인/로그아웃, CSRF, 세션 관리 | 제한적인 전역 설정, 필터 우회 (권장되지 않음) |
필터 체인 | 보안 필터 체인 구성 | 보안 필터 체인 생성 (내부적) |
사용 빈도 | 높음 (주 구성 방식) | 낮음 (대부분 HttpSecurity로 대체) |
사용 사례 | 대부분의 보안 구성 | 특수한 경우의 필터 완전 우회 |
주요 변화 및 권장 사항
- 정적 리소스 처리:
- Spring Security 6.4.5에서는 WebSecurity.ignoring()보다 HttpSecurity.permitAll()을 사용하는 것을 권장합니다.
- 이유: 보안 필터 체인을 통과하되 인증을 요구하지 않는 방식이 필터를 완전히 우회하는 것보다 보안적으로 선호됩니다.
- 필터 순서:
- WebSecurity는 여전히 HttpSecurity 이전에 평가되지만, 사용 사례가 크게 제한되었습니다.
- 구성 방식:
- Spring Security 6.4.5는 람다 기반 DSL을 통한 구성을 강조합니다.
- 메서드 체이닝보다 가독성이 좋고 타입 안전성이 향상된 람다 구성이 권장됩니다.
6. 실제 애플리케이션에서의 활용 방법
Spring Security 6.4.5에서는 다음과 같은 패턴으로 보안을 구성하는 것이 권장됩니다:
@Configuration
@EnableWebSecurity
@EnableMethodSecurity // 메서드 수준 보안 활성화 (이전의 @EnableGlobalMethodSecurity 대체)
public class SecurityConfig {
@Bean
public SecurityFilterChain apiSecurityFilterChain(HttpSecurity http) throws Exception {
http
// securityMatcher(): 이 SecurityFilterChain 자체가 적용될 URL 패턴 정의
// 이 필터 체인은 /api/** 경로에만 적용됨
.securityMatcher("/api/**")
.authorizeHttpRequests(authorize -> authorize
// requestMatchers(): 이미 securityMatcher로 필터링된 URL 중에서
// 특정 패턴에 대한 세부 보안 규칙 정의
.requestMatchers("/api/public/**").permitAll()
.anyRequest().authenticated()
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.csrf(csrf -> csrf.disable()) // API에 대해 CSRF 비활성화
.httpBasic(withDefaults())
.oauth2ResourceServer(oauth2 -> oauth2.jwt(withDefaults()));
return http.build();
}
@Bean
public SecurityFilterChain webSecurityFilterChain(HttpSecurity http) throws Exception {
http
// securityMatcher("/**"): 모든 URL에 이 필터 체인을 적용
// 단, 다른 SecurityFilterChain이 먼저 일치하는 URL 패턴은 제외됨
.securityMatcher("/**")
.authorizeHttpRequests(authorize -> authorize
// requestMatchers(): securityMatcher 내에서 특정 URL 패턴에 대한
// 구체적인 권한 규칙 정의
// 정적 리소스 처리 - 이전 WebSecurity.ignoring() 대체
.requestMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**").permitAll()
// 공개 페이지
.requestMatchers("/", "/home", "/register", "/about").permitAll()
// 관리자 페이지
.requestMatchers("/admin/**").hasAuthority("ADMIN")
// 나머지 요청
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.permitAll()
)
.logout(logout -> logout
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.permitAll()
.clearAuthentication(true)
.invalidateHttpSession(true)
)
.rememberMe(remember -> remember
.key("uniqueAndSecretKey")
.tokenValiditySeconds(86400)
);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.builder()
.username("user")
.password(passwordEncoder().encode("password"))
.authorities("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder().encode("admin"))
.authorities("ADMIN", "USER")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
}
이 예제는 Spring Security 6.4.5의 주요 특징을 보여줍니다:
- 다중 SecurityFilterChain 빈을 통한 경로별 다른 보안 구성
- securityMatcher()를 사용한 필터 체인 자체의 적용 범위 지정
- requestMatchers()를 사용한 SecurityFilterChain 내부에서의 세부적인 URL 보안 규칙 정의
- 람다 기반 DSL을 통한 가독성 높은 구성
- 정적 리소스 처리를 HttpSecurity 내에서 수행
- @EnableMethodSecurity를 통한 메서드 수준 보안 활성화
7. 결론
Spring Security 6.4.5에서 HttpSecurity와 WebSecurity의 관계는 이전 버전과 비교하여 크게 변화했습니다:
- HttpSecurity는 더욱 중심적인 역할을 하며, 거의 모든 보안 구성이 이를 통해 이루어집니다.
- WebSecurity는 사용 범위가 크게 축소되었으며, 대부분의 기능이 HttpSecurity로 이전되었습니다.
Spring Security 6.4.5에서의 주요 권장 사항:
- 정적 리소스 처리:
- WebSecurity.ignoring() 대신 HttpSecurity의 authorizeHttpRequests()와 permitAll()을 사용하세요.
- 다중 보안 구성:
- 여러 SecurityFilterChain 빈과 securityMatcher()를 사용하여 다양한 경로에 대해 서로 다른 보안 구성을 적용하세요.
- matcher 메서드 구분:
- securityMatcher()는 SecurityFilterChain이 적용될 전체 URL 범위를 정의할 때 사용하세요.
- requestMatchers()는 SecurityFilterChain 내에서 세부적인 URL별 보안 규칙을 정의할 때 사용하세요.
- 람다 기반 구성:
- 메서드 체이닝 대신 람다 기반 DSL을 사용하여 더 가독성 높고 유지보수하기 쉬운 코드를 작성하세요.
- 메서드 보안:
- @EnableGlobalMethodSecurity 대신 @EnableMethodSecurity를 사용하세요.
Spring Security 6.4.5의 이러한 변화는 더 명확하고, 타입에 안전하며, 유지보수하기 쉬운 보안 구성을 작성할 수 있게 해줍니다. 이전 버전의 복잡성과 불명확한 부분들이 많이 개선되었으며, 현대적인 접근 방식을 통해 보안 구성의 품질을 높일 수 있게 되었습니다.