웹 서버를 작업 및 관리 도중 오류가 발생했다 하면, 십중팔구 CORS 이 녀석이 문제라고 다들 불만을 토로한다.
그렇다면 도대체 교차 출처 리소스 공유 CORS는 무엇일까 🤔❓
CORS (cross - origin resource sharing)
한 도메인에서 로드되어 다른 도메인에 있는 리소스와 상호 작용하는 클라이언트 웹 애플리케이션에 대한 방법
정보 출처 : Amarzon Web Server
쉽게 정리하자면 타 브라우저에서 다른 출처의 리소스를 공유하는 방법이다.
CORS를 설명하기 전 SOP에 대해서 먼저 짚고 넘어가야 한다.
SOP(Same Origin Policy)
다른 출처의 리소스를 사용하는 것에 제한하는 보안 방식
출처는 URL에서 Protocol, Host, Port를 통해 동일한 출처인지 다른 출처인지 판별이 가능하다.
같은 출처인 경우 Same Origin, 다른 출처인 경우 Cross Origin
추가적으로 설명하자면, 인터넷 익스플로어 같은 경우 Port가 달라도 같은 출처로 판별하므로
SOP 규칙에서 어긋난다. (고로 쓰지마라... 🚫 e 아이콘에 클릭도 하지마라..🚫 🚫 )
그동안 열심히 모았던 팔로워들을 순식간에 잃을 절체 절명의 대위기..
인스타를 자주 이용하는 이용자들에겐 최악의 상황이 벌어진 상태이다.
이를 방지하기 위해 SOP가 중요한 역할을 수행하게 된다.
인스타그램 입장에서는 Origin 출처가 다르므로 Cross Origin이 발동된 관계에 따라
SOP의 절대적 룰이 위반되어 해당 요청을 무시하게 된다.
이렇게 보면 SOP가 새삼 중요하다는 것을 느낄수 밖에,,,,
🚫 SOP에 위반 되는 예시 🚫
- 다른 도메인 (google.com ➡️ WhatIsThat.com)
- 다른 하위 도메인 (gmail.google.com ➡️ WhatIsThat.google.com)
- 다른 포트 (google.com ➡️ google.com:81)
- 다른 프로토콜 (https://google.com ➡️ http://google.com)
그러나 종종 해당 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 필요할 경우
CORS 교차 출처 리소스 공유 정책이 생긴 것이다.
CORS에는 3가지의 접근 제어가 있으며, 각각 자세히 설명하겠다.
프리플라이트는 사전 접근 확인에 가까운 요청이다.
사전 접근 요청은 OPTIONS 메서드를 통해 다른 도메인의 리소스에 접근 요청이 가능한 지 파악하여 확인하는 작업이다.
Preflight Request (사전 요청)
OPTIONS /doc HTTP/1.1
Origin: http://foo.example // 요청 출처
Access-Control-Request-Method: POST // 실제 요청의 메서드
Access-Control-Request-Headers: X-PINGOTHER, Content-Type // 실제 요청의 추가 헤더
위의 내용은 프리플라이트에 사전 요청 전 보내야할 조건이다.
실제 요청(Actual Request)에 보낼 요청을 미리 다 작성해서 요청해놓은 셈이다.
Preflight Response (사전 응답)
Access-Control-Allow-Origin: http://foo.example 서버 측의 허가 출처
Access-Control-Allow-Methods: GET, POST, OPTIONS 서버 측의 허가 메서드
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type 서버 측의 허가 헤더
Access-Control-Max-Age: 86400 응답 캐시 시간
위의 내용은 서버 측에 대한 조건들을 응답 조건으로 걸어둔 내용이다.
응답 캐시 시간에 대해 자세히 설명하자면 해당 시간 동안의 중복 요청 필요 없이
실제 요청(Actual Request)을 바로 허가해주는 조건이다.
만일 해당 조건들이 성립 안했을 경우 발생되는 일
1. CORS 오류 발생
2. 조건이 의도치 않게 simple request 조건에 맞춰진 경우 simple request로 작동됨
그 이유는 CORS를 모르는 서버가 있기 때문이며, 이는 즉 CORS 관련 설정이 아무것도 없는 상태이다.
SERVER는 CORS 설정이 없는 관계로 ALLOW-ORIGIN이 없는 상태이며
브라우저를 통해 CORS 에러를 발생시킨다.
그러나 이미 서버 측에서는 요청 조건을 다 수행한 관계로 DELETE 같은 요청이라면 CORS 에러가 발생 전
데이터를 벌써 지우고 난 후의 상황이므로 데이터를 되돌리기에는 늦어버렸다...
결국 이를 방지하기 위해 사전 요청 OPTIONS을 하여 CORS 에러가 발생했는지
사전에 판별하기 위해 프리플라이트 사전 요청이 중요하게 쓰이는 이유이다.
프리플라이트 요청과 달리 바로 요청을 보내어 Cross-Origin을 판별할 수 있다.
그러나 다음과 같은 조건에만 요청을 보낼 수가 있다.
GET
, POST
, HEAD
application/x-www-form-urlencoded
, multipart/form-data
, text-plain
Accept
, Accept-Language
, Content-Language
, Content-Type
만 허용 가능3가지 조건들이 모두 충족되어야만 단순 요청이 가능하다.
인증 관련 헤더를 포함할 때 사용하는 요청이며, 주로 다른 출처 간 통신에서 강화된 보안을 원할 경우 이용한다.
Client
credentials: include
속성값 | 설명 |
---|---|
same-origin | 같은 출처 간 요청에만 인증 정보를 담는다 |
include | 모든 요청에 인증 정보를 담는다 |
omit | 모든 요청에 인증 정보를 담지 않는다 |
credentials 속성의 기본값은 same-origin
이므로, CORS 정책을 지키기 위해선 include
로 변경해야 한다.
Server
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin : http://foo.example
* 사용 불가credentials: include
는 동일 출처 여부와 상관없이 모든 요청에 인증 정보가 포함되도록
설정되었기 때문에 *
의 모든 출처를 허용하는 것은 사용 불가이다.