1. CORS란?
- Cross Origin Resource Sharing의 약자로 클라이언트 애플리케이션과 다른 origin을 가진 서버 애플리케이션이 서로 통신할 수 있도록 허용하는 프로토콜이다.
- CORS는 웹 개발을 하다가 만날 수 있는 이슈이며 프론트엔드 개발시에 로컬에 API 서버 요청을 보낼 때 생겨나는 문제이다. 서로 다른 도메인 간에 자원을 공유할 떄 대부분 브라우저는 이를 기본적으로 차단하고 서버 측에 헤더를 통해 사용 가능한 자원을 알려준다.
- 예를 들어 클라이언트 애플리케이션 vue로 돌아갈 때 포트번호가 서버 애플리케이션 포트번호와 다르므로 클라이언트와 서버는 다른 origin을 가졌다고 할 수 있다.
- 사실 클라이언트와 서버는 같은 origin을 가진 경우에만 서로 통신할 수 있고 이것을 SOP(Same Origin Policy) 라고 한다. SOP를 하는 이유는 클라이언트와 서버의 origin이 달라도 서버에 접근을 모두 허용하면 클라이언트에서 악의적으로 서버에 접근할 가능성이 매우 큰 문제점이 있기 때문이다.
- 따라서 CORS를 통해 서로 다른 originx에서도 통신이 가능하며 보안적인 문제도 해결할 수 있게 된다.
2. COR의 동작 방식
1) Simple Requests인 경우
- 서버로 요청 시도
- 서버의 응답이 왔을 때 브라우저가 요청한 origin과 응답한 헤더 access-control-request-headers의 값을 비교해 유효한 요청이면 리소스를 응답하고 만약 유효하지 않은 요청이면 브라우저에서 이를 막고 에러가 발생
- SimpleRequests
- SimpleRequests : HTTP Method가 GET/HEAD/POST 중 하나이며, 자동으로 설정되는 헤더는 제외되고 설정할 수 있는 헤더(Accept / Accept-Language / Content-Language)를 변경해 Content-Type(application/x-www-form-urlencoded, multipart/form-data, text/plain)중 하나일 떄 Simple Requests라고 부른다.
- 이러한 요청은 추가적으로 확인하지 않고 바로 요청을 보낸다.
2) preflight의 요청인 경우
- Origin 헤더에 현재 요청하는 origin과 Access-Control-Request-Method 헤더에 요청하는 HTTP method와 Access-Control-Request-Headers 요청시 사용할 헤더를 OPTIONS 메서드로 서버에 요청한다. 이때 내용물 없이 헤더만을 전송한다.
- 브라우저가 서버에서 응답한 헤더를 보고 유효한 요청인지 확인하며 만약 유효하지 않은 요청이라면 요청은 중단되고 에러가 발생한다. 만약 유효한 요청이라면 요청을 다시 하여 리소스 응답을 받는다.
- preflight 요청
- Simple requests가 아닌 cross-origin 요청은 모두 preflight 요청을 하게 되며 실제 요청을 보내는 것이 확인하기 위해 먼저 OPTIONS메서드를 통해 cross-origin HTTP 요청을 보낸다.
- 이렇게 해 사용자 데이터에 영향을 줄 수 있는 있기 때문에 사전에 확인 후 본 요청을 보낸다.
3. Spring Boot + Spring Security에서 cors 처리
1) Spring Boot에서 Global하게 mvc 처리와 관련하여 Configuration으로 해결
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods(
HttpMethod.GET.name(),
HttpMethod.HEAD.name(),
HttpMethod.POST.name(),
HttpMethod.PUT.name(),
HttpMethod.DELETE.name());
}
}
- registry.addMapping을 통해 CORS에 적용할 URL 패턴을 정의한다.
- allowedOrigins 메소드를 통해 자원 공유를 허락할 Origin을 지정할 수 있다.
- 위에 "*"로 모든 Origin을 허락할 수 있다.
- 하지만 이 모두 허락하면 cors를 사용하는 의미가 없으므로 요청하는 클라이언트 도메인에 맞춰 잘 값을 변경하자.
- allowedMethods를 통해 허용할 HTTP method를 지정할 수 있다.
- "*"로 처리하면 모든 method를 허용할 수 있으며, 사용하고 싶은 method를 위처럼 추가할 수도 있다.
- 추가적으로 maxAge 메소드를 통해 원하는 시간만큼 pre-flight 리퀘스트를 캐싱할 수 있다.
2) Spring Boot에서 annotations을 활용
@RestController
@RequiredArgsConstructor
@CrossOrigin(origins = "*", allowedHeaders = "*")
public class MemberController {
//....
}
- 특정 Controller 또는 메소드단에 annotaion을 적용하는 방법이다.
- CrossOrigin이라는 어노테이션으로 global하게 설정했던 것과 마찬가지로 origins나 methods를 지정할 수 있다.
3) Spring Boot에서 Spring Security내에
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().disable() // rest api만을 고려해 기본 설정은 해제
.csrf().disable() // csrf 보안 토큰 disable 처리
// 다른 시큐리티 설정
.and()
.cors()
// 다른 시큐리티 설정;
}
}
- WebSecurityConfigurerAdapter 를 implements 하는 SecurityConfig부분 중 configure 메소드 안에 .and().cors()를 넣어주면 시큐리티에서도 cors 문제 없이 잘 적용할 수 있다.
'CS > 컴퓨터네트워크' 카테고리의 다른 글
HTTP와 HTTPS의 개념과 차이점에 대하여 (0) | 2022.07.31 |
---|---|
HTTP 상태코드 (0) | 2022.07.10 |
URI와 웹 브라우저 요청 흐름 (0) | 2022.07.10 |