CORS

김효식 (HS KIM)·2022년 1월 12일
0

프론트엔드 개발을 하다 보면 백엔드 서버에 요청을 보냈을 때, 콘솔창에 빨갛게 CORS에러가 뜨는 것을 자주 목격하게 된다. CORS를 대응하는 방법을 알지 못한다면, 클라이언트가 에러를 해결하기 위해 여러가지 다양한 시도를 해봐도 원하는대로 동작하지 않아 난감하기 짝이 없을 것이다. 클라이언트에서도 작업을 해줘야 되지만, 근본적인 문제 해결은 서버에서 해결 해야한다.

SOP

CORS를 알기 전에 SOP에 대해 알아야 한다. SOPSame Origin Policy의 약자로, 해석하면 동일 출처 정책이다. 여기서 말하는 출처란 urlscheme, host, port 까지를 말한다. 따라서, 동일 출처라는 것은 요청을 보내는 urlscheme, host, port과 요청을 보내는 urlscheme, host, port가 같은 것을 말한다.

http://localhost:80
http://localhost:80/login

위의 두 urlpath만 다르므로 same origin이다.

이전에 서버에 요청을 보내서 html 정적파일을 받았을 때는, 클라이언트와 서버의 url이 당연히 같을 수 밖에 없었다. 그렇기 때문에, 클라이언트와 서버의 출처가 다르면 외부의 해킹일 가능성이 높다고 생각했다.

다른 출처에 대한 제재가 없다면 원래 클라이언트 url의 쿠키 정보를 통해 원래 요청하려던 서버의 중간에 다른 서버를 거쳐서 클라이언트의 정보를 악용할 수 있는 가능성이 있다. 그래서 두 url의 출처가 다른 경우에 제재를 가할 필요가 있었고, 그 결과 동일 출처 원칙인 SOP가 생겨난 것이다.

CORS의 등장

이후 웹에서 html파일을 정적으로만 받지 않고, 웹 애플리케이션을 만들기 시작하면서 백엔드 서버 말고 다른 url에도 요청을 보낼 일이 생기기 시작했다. 다른 누군가 만든 서버의 url은 내가 만든 클라이언트의 url과 당연히 다르므로 응답을 받을 수 없었다.

그래서 지금은 잘 사용되지 않지만 한동안 JSONP라는 script태그를 사용하여 우회하는 방법으로 응답을 받는 처리를 했다. 이후에 결국 등장하여 우회하는 방법이 아닌 공식적인 방법으로 다른 출처의 요청을 허용하게 해주는 것이 CORS(Cross Origin Resource Sharing이다. CORS 에러 메시지를 보고 CORS를 에러라고 생각할 수 있지만, 에러를 유발하는 것은 SOP이고 CORS는 에러가 아니라 에러를 해결하는 방법이다.

CORS 에러

프론트엔드에서 CORS 문제를 해결하기 위해 프록시 서버를 통해 우회하는 방법이 있긴 하지만, 근본적인 해결책은 아니다. 백엔드 서버에서 다른 출처의 접근도 허용하게 하기 위해서는 접근을 허용해줄 다른 출처에 대해 명시해주면 된다.

서버가 보내는 response에는 Access-Control-Allow-Origin 이라는 값이 있는데, *를 값으로 주면 모든 url에서 접근이 가능하고, 아니면 프론트엔드와 사전에 협의한 url을 값으로 주면 된다. 백엔드 서버를 위해 사용하는 대부분의 라이브러리에서는 CORS 문제에 대응하기 위한 방법들이 이미 마련되어 있기 때문에, 공식문서를 보고 비교적 손쉽게 문제를 해결할 수 있다.

브라우저는 서버에 request를 보낼 때, 다른 출처의 요청일 경우에 headerorigin이라는 항목을 추가한다. 서버는 response에 브라우저로 부터 받은 origin과 위에서 말한 Access-Control-Allow-Origin을 같이 헤더에 보낸다. 서버는 동일 출처를 검사하지 않고 응답을 보낸다.

originAccess-Control-Allow-Origin 을 검사하는 것은 서버가 아닌 브라우저의 역할이다. 두 출처를 검사하여 SOP에 위배되면 브라우저는 responsebody의 값을 공개하지 않고, CORS에러를 발생시킨다.

동일한 origin의 경우에는 http통신을 하면 쿠키가 요청 header에 자동으로 포함된다. 그런데 origin이 다른 경우에는, 자동으로 포함되지 않기 때문에 전송하기 위해서는 직접 별도로 넣어줘야 한다. 프론트엔드는 headercredentials: true를 추가해주고, 백엔드 서버는 responseheaderAccess-Control-Allow-Credentials: true 를 추가해주면 된다.

일반적인 요청의 경우에는 위와 같이 요청을 보내고 이를 simple request라고 한다. 일반적이지 않은 요청이라고 간주되는 것은 꽤 복잡한데, 주로 요청 메서드가 GET, POST, HEAD가 아닌 요청들이다. 이런 요청들은 보내기 전에 요청을 보낼 수 있는지 확인하는 사전 요청을 보내는데 이를 preflight request라고 한다. preflight 요청은 브라우저가 자동적으로 생성하기 때문에 별도로 생성할 필요가 없고 사전 요청을 통해 요청을 보낼 수 있는지 서버에 확인하고, 원래 요청을 보낸다.

profile
자기개발 :)

0개의 댓글