CORS란 말 그대로 origin이 다른 경우에도 리소스를 공유할 수 있게 허용해주는 정책을 의미한다. 여기서 origin이란 프로토콜 + 호스트 + 포트를 합한 것으로 이 세가지가 동일하면 같은 origin이라고 판단한다.
예를 들어, http://123.456.789.123:3000
과 http://123.456.789.123:8001
은 서로 다른 origin이다.
과거에는 프론트엔드와 백엔드가 같은 서버에서 운영되었기에 동일한 origin간의 통신을 했는데, 프론트엔드와 백엔드가 각각 다른 서버에서 운영되면서 문제가 발생하기 시작했다.
별도로 존재하는 프론트엔드 서버에서 백엔드 서버로 요청(request)이 이뤄져야 하는 상황이 발생했고, 동시에 어떤 곳에서 백엔드 서버로 요청이 올지 알 수 없게 되었다.
따라서 백엔드 서버쪽에서 어떤 origin에서 요청을 했을 때 받아줄 것인지 허용 origin에 대해 정의해 줄 필요가 생겼다.
백엔드 서버 :
"나는 이 origin에서 이뤄지는 요청만 처리해 줄 거야. 다른 origin은 믿을 수 없어. 해커가 날 공격할 수 도 있잖아?"
이 때, 프론트엔드에서 백엔드쪽으로 요청을 보낸 이후에만 허용된 origin인지 아닌지를 알 수 있는 상황이어서 문제가 되었다. 애초에 요청 자체를 못하게 막을 방법이 필요했고, 그래서 나온것이 preflight request이다.
preflight request는 실제 요청전에 브라우저에서 보내는 작은 요청이다. 이 요청의 목적은 다음과 같다.
백엔드 서버가 해당 origin과 메서드를 허용하는 경우에만 실제 요청이 이루어지며, 그렇지 않다면 실제 요청을 보내기도 전에 보내지 못하게 차단하는 것이다.
preflight request 덕분에, 허용되지 않은 origin에서의 요청은 미리 차단되므로 서버에 불필요한 접근이 줄어들고 보안성이 강화되었다.
아래 그림을 보면 preflight request가 무엇인지 이해하는데 도움이 된다.
preflight request는 OPTIONS 메서드에 의해 만들어지기 때문에, preflight request가 이뤄지려면 서버에서 OPTIONS 메서드를 허용 해주어야 한다.
aws에서 해당 인스턴스의 권한으로 들어가면 CORS가 나오게 된다.
편집을 누르고 아래와 같이 Access-Control-Allow-Methods
부분에 OPTIONS 메서드를 허용해주면 된다.
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"GET",
"HEAD",
"OPTIONS" // <- OPTIONS 추가.
],
"AllowedOrigins": [
"http://www.example.com"
],
....
}
]
또한, 해당 프로젝트에선 JWT 토큰을 검증하기 위해 JwtFilter를 구현해두었으며 모든 요청은 JwtFilter를 타게 되어있다.
public class JwtFilter extends OncePerRequestFilter {
private static final String BEARER = "bearer";
....
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
if (CorsUtils.isPreFlightRequest(request)) {
filterChain.doFilter(request, response);
return;
}
....
하여 doFilterInternal
이라는 메서드에 if 조건문을 달아 해당 요청이 preFlightRequest라면 return을 하도록 구현하도록 했다.