한 도메인 또는 Origin이 다른 도메인을 가진 리소스에서 액세스 할 수 있게 하는 보안 메카니즘으로써 서버와 클라이언트가 정해진 헤더를 통해 서로 요청이나 응답에 반응할지 결정하는 방식이다.
동일출처정책?
동일한 출처의 리소스에만 접근하도록 제한하는것 동일출처라는 것은 프로토콜, 호스트명, 포트가 같다는 것을 의미한다.
내가 배포한 서버의 주소는 포트가 8080인 주소인데, request하는 주소는 포트가 3000인 주소라 동일출처가 아니기에 일어나는 에러였다.
SecurityFilterChain 내부의 http의 .sameOrigin()
SecurityFilterChain 내부의 CorsConfigurationSource 에서 CORS 정책
스프링시큐리티에서 지원하는 인증과 권한부여설정을 하기위해서는 SecurityConfiguration class를 사용하여 정의하게된다.
그 중 SecurityFilterChain을 이용할 수 있는데, 이것은 HTTP보안설정을 구성할 수 있게해준다.
public class SecurityConfiguration{
.
.
.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.headers().frameOptions().sameOrigin() --------> (1)
.and()
.csrf().disable()
//기본적으로 아무설정을 하지 않으면 csrf 공격을 받음 클라이언트로부터 CSRF 토큰을 수신 후 검증
.cors()
.and()
//세션을사용하지 않도록 설정함
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.formLogin().disable()
.httpBasic().disable()
.exceptionHandling()
.authenticationEntryPoint(new MemberAuthenticationEntryPoint())
.accessDeniedHandler(new MemberAccessDeniedHandler())
.and()
.apply(new CustomFilterConfigurer())
.and()
.authorizeHttpRequests(autorize -> autorize
.antMatchers(HttpMethod.PATCH, "/members/**").hasRole("USER")
.antMatchers(HttpMethod.GET, "/members").hasRole("ADMIN")
.antMatchers(HttpMethod.GET, "/members/**").hasAnyRole("USER", "ADMIN")
.antMatchers(HttpMethod.DELETE, "/members").hasRole("USER")
.antMatchers(HttpMethod.POST, "/blogs").hasRole("USER")
.antMatchers(HttpMethod.POST, "/questions").hasRole("USER")
.antMatchers(HttpMethod.POST, "/blogs/answer").hasRole("USER")
.antMatchers(HttpMethod.POST, "/questions/answer").hasRole("USER")
.anyRequest().permitAll()//JWT 적용전 우선 허용
);
return http.build();
}
- Spring Security에서는 Clickjacking 공격을 막기 위해 기본적으로 frameOptions() 기능이 활성화되어 있으며 디폴트 값은 DENY이다.
- (1)과 같이 .frameOptions().sameOrigin()을 호출하면 동일 출처로부터 들어오는 request만 페이지 렌더링을 허용하게된다.
따라서 배포시에는 해당 코드를 주석처리하던지, .sameOrigin()대신에 .disable()를 해줘야 cors에 걸리지 않게 된다.
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.addAllowedOriginPattern("*"); ----------->(1)
configuration.setAllowedHeaders(Arrays.asList("*")); --------------->(2)
configuration.setExposedHeaders(Arrays.asList("*")); --------------->(3)
configuration.setAllowCredentials(true); ------------------->(4)
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PATCH", "DELETE"));//해당 메서드허용
configuration.setExposedHeaders(Arrays.asList("Authorization", "Refresh")); -------------->(5)
//CorsConfigurationSource 인터페이스의 구현클래스임
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
//앞에서 구현한 CORS 정책 적용
source.registerCorsConfiguration("/**", configuration);
return source;
}
위에서 사용한 메서드들은 다음과 같다.
- addAllowedOriginPattern
- setAllowedHeaders
- setExposedHeaders
- setAllowCredentials
- setAllowedMethods
- setExposedHeaders
authorization 과 refresh가 새로 노출된것을 확인 할 수 있다.
ref : https://bohyeon-n.github.io/deploy/web/cors.html
https://oddpoet.net/blog/2017/04/27/cors-with-spring-security/