[CORS] CORS는 무엇일까?
풀스택으로 웹 개발 프로젝트를 진행하면서 CORS라는 에러를 마주쳤다.
살면서 처음보는 에러였다.
CORS는 대체 뭐하는 녀석일까?
풀 네임은 Corss-Origin Resource Sharing이다.
보안상의 이유로 JavaScript에서 보내는 교차 출처의 HTTP 요청을 제한하는 정책이다.
대부분의 브라우저에 이 CORS라는 것이 적용되어있다.
교차 출처라는 것이 무엇인지 정확히 몰라서 찾아봤더니 예시를 들어보면 이렇다.
http://localhost:3000 에서 http://www.example.com/ 이라는 곳에 요청을 보내면 CORS 에러가 발생한다.
요청의 출처는 localhost:3000 인데 동일한 출처가 아닌 www.example.com 에 요청을 보냈기 때문이다.
같은 출처가 아닌 곳에서의 요청은 어떤 위험한 요청을 포함하고 있을지 모르기에 보안상 막아 놓은 것이다.
포트 번호가 달라도 CORS 에러가 발생한다.
http://localhost:3000 에서 http://localhost:5000 으로 요청을 보낼 때에도 CORS 에러가 발생한다.
출처가 일치해야만 CORS가 발생하지 않는데, 출처는 어디까지를 말하는걸까?
http://localhost:3000/api/users?id=1#desc
위와 같은 URL이 있다고 한다면 다음과 같이 구분된다.
Protocol -> http://
Host -> localhost
Port -> 3000
Path -> /api/users
Query -> ?id=1
Fragment -> #desc
출처는 Protocol, Host, Port 를 의미한다. 저 세 가지가 모두 일치해야만 같은 출처라고 보는 것이다.
CORS는 내부적으로 어떻게 동작할까?
우선 CORS의 동작 방식에는 두 가지 종류가 있다.
1. Preflight Request
클라이언트가 서버에 요청을 보내기 전에 예비요청을 먼저 보낸다.
서버에게 HTTP의 OPTIONS 메소드로 먼저 요청을 보낸다.
만약 요청을 보낸 곳이 CORS 정책을 위반하지 않는 출처라면 서버는 클라이언트에게 안전하다는 응답을 보낸다.
안전하다는 응답을 받았다면 클라이언트는 본 요청을 다시 서버로 보낸다.
웹 개발을 하면서 별다른 설정을 해놓지 않았다면 기본적으로 이 방법이 적용될 것이다.
레이서 포트폴리오 프로젝트를 진행하면서 요청을 한 번 보낼때마다 OPTIONS라는 메소드를 포함해 두 번씩 요청이 갔었는데 그게 이런 이유 때문이었다.
2. Simple Request
Preflight Request와 달리 예비 요청을 보내지 않는다.
Access-Control-Allow-Origin 이라는 헤더를 이용해 CORS 위반 여부를 검사한다.
클라이언트가 서버에 요청을 보내면 서버는 Access-Control-Allow-Origin 헤더에 CORS 정책에 대한 내용을 포함해서 응답한다.
브라우저가 이 응답을 받고 만약 CORS 위반이 아니라고 판단되면 정상적으로 요청이 마무리된다.
그러면 같은 출처가 아닌 곳에서의 요청을 허용할 수 있는 방법은 없을까?
당연히 있다. 여기에도 방법이 두 가지가 있다.
서버에서 해결하는 방법과 클라이언트에서 해결하는 방법이다.
1. 서버에서 해결하는 방법
우선 서버가 어떤 프레임워크를 사용하는지에 따라 다르다.
다른 블로그의 글을 찾아보면 스프링 같은 경우는 @CrossOrigin 어노테이션을 사용해서 CORS를 해결한다고 한다.
내가 사용했던 Flask 의 경우는 flask_cors 모듈을 설치해서 CORS() 함수를 사용하면 해결할 수 있다.
CORS(app, resources={r'*': {'origins': '*'}}) 모든 출처에서 접근을 허용한다.
CORS(app, resources={r'*':{'origins': 'http://localhost.com'}}) http://localhost.com 에서 오는 접근을 허용한다.
CORS(app, resources={r'/api/*':{'origins': '*'}}) /api 로 들어오는 요청은 모든 출처에서 접근을 허용한다.
CORS(app, resources={r'/api/*':{'origins': 'http://localhost.com'}}) /api 로 들어오는 요청은 http://localhost.com 로부터 접근을 허용한다.
2. 클라이언트에서 해결하는 방법
CORS 에러는 기본적으로 다른 출처에서 HTTP 요청을 했을 때 발생한다.
따라서 프록시를 이용해 출처를 바꿔버리면 CORS 에러를 피할 수 있다.
서버에게 요청을 보낼 때 CORS가 허용되는 곳으로 프록시 패스를 설정해주면 간단하게 CORS 문제를 해결할 수 있다.
둘다 해결 방법이 될 수 있으나 아무래도 보안적인 부분을 다루는 것이기 때문에 서버에서 처리하는 방법이 더 권장된다고 한다.
[참고]