cross-origin 이란?
출처(origin)이란 Protocol, Host, Port 를 합친 것을 말한다.
즉, cross-origin 이란 다음 중 한 가지라도 다른 경우를 말한다.
1. 프로토콜
ex) http 와 https 는 프로토콜이 다름
2. 도메인
3. 포트 번호
CORS 란?
브라우저에서 cross-origin 요청을 안전하게 할 수 있도록 하는 메커니즘이다.
브라우저에서는 보안적인 이유로 cross-origin HTTP 요청들을 제한한다. 그래서 cross-origin 요청을 하려면 서버의 동의가 필요하다. 만약 서버가 동의한다면 브라우저에서는 요청을 허락하고, 동의하지 않는다면 브라우저에서 거절한다.
이러한 허락을 구하고 거절하는 메커니즘을 HTTP-header 를 이용해서 가능한데, 이를 CORS(Cross-Origin Resource Sharing) 라고 부릅니다.
동일 출처 정책(Same-Origin Policy, SOP) 란?
브라우저를 거치지 않고 Postman으로 API를 테스트할 때는 잘 동작하다가 브라우저에서 API를 호출하면 CORS policy 오류가 발생할 때가 있다. 그 이유는 브라우저가 동일 출처 정책을 지켜서 다른 출처의 리소스 접근을 금지하기 때문이다. 동일 출처 정책을 지키면 외부 리소스를 가져오지 못해 불편하지만, XSS나 CSRF 등의 보안 취약점을 노린 공격을 방어할 수 있다. 하지만 현실적으로 외부 리소스를 참고하는 것이 꼭 필요하기 때문에 외부 리소스를 가져올 수 있는 방법이 존재해야 하고, 그를 위한 예외 조항이 CORS 이다.
CORS 동작 원리
CORS 동작 방식은 단순 요청 방법(Simple Request)과 예비 요청(Preflight request)을 먼저 보내는 방법 2가지가 있다.
Simple Request - 단순 요청 방법
1. 서버로 요청한다.
2. 서버의 응답이 왔을 때 브라우저가 요청한 Origin과 서버가 응답한 헤더의 Access-Control-Request-Headers의 값을 비교하여 유요한 요청이라면 리소스를 응답한다. 만약 유효하지 않은 요청이라면 브라우저에서 이를 막고 에러가 발생한다.
Simple Request 조건
- 요청 메서드(method)는 GET, HEAD, POST 중 하나여야 합니다.
- Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, Width를 제외한 헤더를 사용하면 안 됩니다.
- Content-Type 헤더는 application/x-www-form-urlencoded, multipart/form-data, text/plain 중 하나를 사용해야 합니다.
첫번째 조건은 어렵지 않지만 두번째, 세번째 조건은 까다로운 조건이다. 두번째 조건은 사용자 인증에 사용되는 Authorization 헤더도 포함되지 않아 까다로운 조건이며, 3번 조건은 많은 REST API들이 Content-Type으로 application/json을 사용하기 때문에 지켜지기 어려운 조건이다.
Preflight request
1. Origin헤더에 현재 요청하는 origin을 담고, Access-Control-Request-Method 헤더에 요청하는 HTTP method를 담고 Access-Control-Request-Headers 요청 시 사용할 헤더를 OPTIONS 메서드로 서버로 요청한다. 이때 내용물은 없이 헤더만 전송한다.
2. 브라우저가 서버에서 응답한 헤더를 보고 유효한 요청인지 확인한다. 만약 유효하지 않은 요청이라면 요청은 중단되고 에러가 발생한다. 만약 유효한 요청이라면 원래 요청으로 보내려던 요청을 다시 요청하여 리소스를 응답 받는다.
GET, POST, PUT, DELETE 등의 메서드로 API를 요청했는데, 크롬 개발자 도구의 네트워크 탭에 OPTIONS 메서드로 요청이 보내졌다면 CORS를 경험한 것이다. Preflight 요청은 실제 리소스를 요청하기 전에 OPTIONS라는 메서드를 통해 실제 요청을 전송할지 판단 한다.
OPTIONS 메서드로 서버에 예비 요청을 먼저 보내고, 서버는 이 예비 요청에 대한 응답으로 Access-Control-Allow-Origin 헤더를 포함한 응답을 브라우저에 보낸다. 브라우저는 단순 요청과 동일하게 Access-Control-Allow-Origin 헤더를 확인해서 CORS 동작을 수행할지 판단한다.
요청 헤더 목록
- Origin
- Access-Control-Request-Method
- preflight 요청을 할 때 실제 요청에서 어떤 메서드를 사용할 것인지 서버에게 알리기 위해 사용 된다.
- Access-Control-Request-Headers
- preflight요청을 할 때 실제 요청에서 어떤 header를 사용할 것인지 서버에게 알리기 위해 사용 된다.
응답 헤더 목록
- Access-Control-Allow-Origin
- 브라우저가 해당 origin이 자원에 접근할 수 있도록 허용합니다. 혹은 *은 credentials이 없는 요청에 한해서 모든 origin에서 접근이 가능하도록 허용 한다.
- Access-Control-Expose-Headers
- 브라우저가 액세스할 수 있는 서버 화이트리스트 헤더를 허용 한다.
- Access-Control-Max-Age
- 얼마나 오랫동안 preflight요청이 캐싱 될 수 있는지를 나타낸다.
- Access-Control-Allow-Credentials
- Credentials가 true 일 때 요청에 대한 응답이 노출될 수 있는지를 나타낸다.
- preflight요청에 대한 응답의 일부로 사용되는 경우 실제 자격 증명을 사용하여 실제 요청을 수행할 수 있는지를 나타낸다.
- 간단한 GET 요청은 preflight되지 않으므로 자격 증명이 있는 리소스를 요청하면 헤더가 리소스와 함께 반환되지 않으면 브라우저에서 응답을 무시하고 웹 콘텐츠로 반환하지 않는다.
- Access-Control-Allow-Methods
- preflight요청에 대한 대한 응답으로 허용되는 메서드들을 나타낸다.
- Access-Control-Allow-Headers
- preflight요청에 대한 대한 응답으로 실제 요청 시 사용할 수 있는 HTTP 헤더를 나타낸다.
출처
https://hannut91.github.io/blogs/infra/cors
CORS란 무엇인가? – Yunseok's Dev Blog
hannut91.github.io
https://beomy.github.io/tech/browser/cors/
[Browser] CORS란?
교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)에 대해 살펴보도록 하겠습니다.
beomy.github.io
'백엔드 > 네트워크' 카테고리의 다른 글
GET 과 POST의 차이 (0) | 2022.06.12 |
---|---|
HTTP 메소드 정리 (4) | 2022.06.10 |