CORS (Cross-Origin Resource Sharing)
란, 브라우저상에서 서로 다른 출처들의 리소스 공유를 허락해 주는 정책입니다.
브라우저상의 웹 사이트에서 ajax, fetch, axios 등으로 HTTP 요청을 보낼 때, 다음과 같은 콘솔 에러를 만난 적이 있다면 CORS 정책에 위반한 것입니다.
Access to fetch at ‘https://test.com’ from origin ‘http://localhost:3000’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.
리소스의 구체적인 위치는 URL로 알 수 있습니다. 출처(Origin)
란 포트번호까지의 주소이며 서버의 위치를 나타냅니다.
URL은 크게 세 부분으로 이루어진 표준 포맷을 따릅니다.
스키마(scheme)
: 리소스에 접근하기 위해 사용되는 프로토콜을 서술합니다. 보통 http 프로토콜입니다. 예시) http://호스트 명+포트번호
: 서버의 인터넷 주소가 주어집니다. 예시) www.test.com:8090리소스 경로
: 웹 서버의 리소스의 경로를 알려줍니다. 예시)/step1/step2예시의 url에서는 http://www.test.com:8090
가 출처입니다.
CORS는 서로 다른 출처들의 리소스 공유를 허락하는 정책입니다. 그렇다면 기본이 되는 정책은 "같은 출처에서만 리소스 공유를 허락한다" 일 것입니다. 이 정책이 SOP(Same-Origin Policy)
이며, 2011년 RFC 6454에서 처음 등장한 보안 정책입니다.
크롬, 사파리, 파이어폭스 등과 같은 브라우저들은 사용자가 방문하는 사이트들 또는 요청하는 API들을 신뢰하지 않습니다.
웹 사이트에 접속하면 브라우저에 해당 사이트의 HTML, CSS, Javascript, 이미지 파일 등의 리소스가 다운로드 받아집니다. 만약 자바스크립트에 악성 코드가 숨겨져 있다면 브라우저의 임시 저장소에 저장된 사용자의 개인 정보가 유출될 수도 있습니다. 브라우저는 이를 방지하기 위해 SOP 정책에 따라 다른 출처의 리소스를 사전 차단시킵니다.
그러나 웹 생태계가 다양해지면서 자유롭게 리소스를 주고 받기 위해서는 예외적으로 다른 출처의 리소스를 받아야 합니다. 다른 출처의 리소스를 받으려면 브라우저의 허락을 먼저 맡아야 합니다. 그 허락이 CORS 정책입니다. CORS 정책을 지킨 요청과 응답은 출처가 다르더라도 리소스 공유가 허락됩니다.
SOP, CORS 모두 브라우저의 정책이므로, 브라우저를 거치지 않는 클라이언트-서버간의 통신에는 CORS 에러가 나지 않습니다.
클라이언트 요청은 크게 두가지로 나눌 수 있습니다.
기본적으로 웹에서의 클라이언트 요청은 대부분 HTTP 프로토콜을 사용합니다. 이때 다른 출처에 보내는 요청일 경우, 브라우저는 HTTP 메시지 헤더에 Origin
필드를 추가해 요청하는 쪽의 출처를 담아 보냅니다.
요청을 받은 서버는 Access-Control-Allow-Origin
필드에 허락할 출처들의 정보를 담아 클라이언트에게 HTTP 응답 메시지를 보냅니다.
브라우저는 Origin의 출처가 Access-Control-Allow-Origin 정보들에 포함되어 있는 경우에만 안전한 요청으로 간주하고, 응답 데이터를 받습니다. 만약 포함되어 있지 않을 경우에는 CORS 정책 위반 에러를 표시합니다.
GET, POST 등 일반적인 simple request들은 일단 요청을 보내고 응답을 받아오지만 브라우저 선에서 데이터를 받을지 말지 결정합니다.
토큰과 같이 사용자 식별 정보가 담긴 요청에서는 보다 엄격하게 확인합니다. 요청 옵션에 credentials 항목을 true로 설정하고, 받는 쪽에서는 Access-Control-Allow-Credentials 항목을 true로 맞춰줘야 합니다.
PUT이나 DELETE등과 같이 서버의 데이터에 영향을 줄 수 있는 요청들은, 본 요청을 보내기전에 preflight 요청
을 보내서 본 요청이 안전한지 확인하고 여기서 브라우저의 허락이 떨어져야 본 요청을 보낼 수 있습니다.
참조
MDN-CORS
많은 것을 배웠습니다, 감사합니다.