CORS(Cross-Origin Resource Sharing)는 웹 보안 정책의 한 측면으로, 웹 브라우저에서 실행되는 스크립트가 다른 도메인의 리소스에 접근하는 것을 제어하는 메커니즘이다.
웹 애플리케이션은 보안상의 이유로 기본적으로 동일 출처 정책(SOP: Same-Origin Policy)에 따라 동일한 출처(프로토콜, 호스트, 포트가 동일한 경우 - http://www.site.com:80
)의 리소스에만 접근할 수 있다. 쉽게 말하면 개인 정보를 보호하기 위해 문을 잠그는 것과 비슷한 아이디어인데, 실제로는 다른 도메인의 리소스에 접근해야 할 경우가 많아 이 때 CORS가 사용된다.
CORS는 웹 브라우저에서만 작동하며, 서버 간의 통신에서 발생하는 보안 이슈를 다룬다. 기본적으로, 웹 페이지의 JavaScript 코드가 다른 도메인의 리소스에 HTTP 요청을 보내면, 브라우저는 보안상의 이유로 해당 요청을 차단한다. 이를 CORS 정책 위반으로 간주한다. CORS는 이러한 제약을 완화하기 위해 다음과 같은 방식으로 동작한다.
// 예시 서버 응답 헤더 설정 (도메인 B)
Access-Control-Allow-Origin:https://domain-a.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 3600
위의 설정은 도메인 A (https://domain-a.com
)에서 오는 GET, POST, PUT 요청을 허용하고, Content-Type 헤더를 허용한다. Access-Control-Max-Age는 브라우저가 CORS 요청 결과를 캐시할 시간을 지정한다.
// 예시 클라이언트 요청 코드 (도메인 A)
fetch('https://domain-b.com/api/data
')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
클라이언트에서 요청을 보낼 때, 브라우저는 "preflight" 요청을 보내 CORS 정책을 검사한다. 서버가 허용하는 도메인 및 메서드, 헤더와 일치하면 실제 데이터를 가져올 수 있게 된다.
위 과정을 사진으로 보면 이해가 빠르다.
SOP를 준수하기 위해 CORS를 사용해 Preflight 요청을 매번 서버에 보내어 도메인에서 응답을 받아야 하는가? 답은 그렇지 않다. 서버에서 헤더와 함께 Preflight 요청을 보낼 때 옵션으로 "Access-Control-Max-Age"의 지정해 Preflight 요청을 캐시할 수 있다. 만약 값을 3600으로 지정한다면 1시간 동안 브라우저에 캐시되어 요청시 값을 읽어 CORS 검사를 생략하고 실제 요청을 보낸다. 이 시간을 길게 지정하면 서버에서 보안 및 정책을 변경할 때 반영이 힘들다는 단점이 있으니, 합리적으로 시간을 지정해야 한다.