참고자료
교차 출처 리소스 공유
- 브라우저가 자신의 출처가 아닌 것들로 부터 요청을 서버가 허용 해주는 HTTP 해더 메커니즘
- 즉 클라이언트 쪽에서 서버의 요청을 허용할 것인지를 결정하게 된다
CORS 애러 이유
결론부터 말하면 CORS 정책을 지키지 않은 요청으로 인해서 발생한다
백엔드에서 응답줄 때Access-Control-Allow-Origin
해더를 설정해야 함
동일 출처 정책 (Same-Origin)
웹이 구동중인 서버와 HTTP 요청을 통해 불러오는 리소스가 서로 동일한 서버 여야 하는 경우
즉 요청이 내 서버에서 일어난거 아니면 오류 내뿜게 되는
- 동일 출처의 조건은
HTTP/HTTPS
,호스트
,포트
까지 모두 동일한것을 의미 - 브라우저의 JS 의
fetch
와XMLHttpRequest
는 기본적으로 해당 정책을 준수 한다 - 하지만 당연하게도 웹에선 필히 외부 요청을 통해 리소스를 가져올 수 있어야한다
- 다른 출처 리소스를 불러올때는 반드시 CORS 정책을 지켜서 요청을 보내야 한다
어떤 것들이 해당하는가
- 브라우저의 JS 의
fetch
와XMLHttpRequest
- 웹 폰트 등등
설명
- Node.js 의 fetch 나 기타 다른 언어들의 HTTP Reqests 에는 해당 되지 않는다
- 이런 조건으로 서버 쪽에서는 다른 웹 서비스가 내 REST API를 이용 할 수 있도록 설정 하거나 제한 할 수 있다는 이점도 가진다
- 그러나 CORS는 웹 브라우저 엔진에서만 작동하는거라 어떠한 불특정 다수의 DDOS 공격을 막거나 하는것은 불가하다
- 왜냐면 그냥 브라우저가 아닌 상황에서의 HTTP Reqests애서는 CORS 가 의미 없기 때문
이렇게 해둔 이유?
- 만약 아무렇게나 요청을 할 수 있다라고 가정하면
- 피싱사이트를 개설한 다음 네이버에 요청을 한다고 가정한다
- 그럼 네이버에 POST 요청을 보내서 브라우저의 저장된 쿠키로 로그인 한다던가 하는게 가능하지 않겠나?
- 브라우저가 아닌 환경에서는 쿠키를 얻는것이 쉽지 않기에 상관 없지만 브라우저는 아니기 때문에
CORS 정책
요청/응답 시 저정된 특수 해더를 붙어야 한다
과정
- 브라우저측 요청 (Fetch() 사용)
GET /resources/public-data/ HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Connection: keep-alive Origin: https://foo.example
- 여기서 핵심은
Origin
, 현재 요청의 원본 주소를 가르킨다
- 여기서 핵심은
- 서버 측 응답
HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 00:23:53 GMT Server: Apache/2 Access-Control-Allow-Origin: * Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: application/xml
- 여기서 핵심은
Access-Control-Allow-Origin
, 해당 응답의 접근 가능한 주소 목록을 나타낸다 *
이면 모든 것들 허용
- 여기서 핵심은
설명
Fetch
함수에서 자동으로 Origin해더를 붙여 원본 주소를 포함한 정보를 서버에 요청을 보낸다- 서버 쪽에서 응답을 받으면
Access-Control-Allow-Origin
의 자신의 도메인(ip) 정보가 있는지 파악한다 - 없는 경우 해당 리소스의 접근 권한이 없다 판단하여 CORS 애러를 내뿜는다
CORS 해더
클라이언트 요청
API 가 자동으로 설정해줌
Origin: IP | Domain
:- 클라이언트 원본 주소
Access-Control-Request-Method
:- 어떤 메소드 인지
Access-Control-Request-Headers
:- 어떤 해더에 접근하려는 건지
서버 측 응답
Access-Control-Allow-Origin: [IP | Domain | *]
:- 해당 호스트의 리소스 접근을 허용하는
- CORS 의 핵심
Access-Control-Expose-Headers: [Heders...]
:- 접근가능한 해더 목록 노출
Access-Control-Allow-Methods: [HTTP Methods...]
:- 허용하는 HTTP Method
Access-Control-Max-Age: Mills
:- 응답 캐싱 시간
- Preflight의 응답을 케싱 하려면 설정 필요
Access-Control-Allow-Credentials: boolen
:- 아래 Credentialed Request 를 사용할 경우
ture
로 설정
- 아래 Credentialed Request 를 사용할 경우
예비 요청 (Preflight)
브라우저가 요청 보낼 때 한번에 바로 보내지 않고 먼저 예비 요청을 하는 과정
- Preflight 는
OPTIONS
메소드를 사용하여 요청한다 - 해당 요청으로 서버가 지원하는
Access-Control-Allow-Origin
,Access-Control-Allow-Methods
정보들을 안전확보 후 본 요청을 보내게 - 하지만 여기서 문제는 응답 시간인데 결국 2번 요청을 보내는 거니까 해결을 위해
Access-Control-Max-Age
해더를 서버측에 설정하면 Preflight 응답을 케싱 할 수 있다
단순요청 (Simple Request)
위 Prefilght 과정 없이 다이렉트로 요청하는
아래 조건을 만족시켜면 Preflight 과정 없이 진행된다
가능 조건
:- 메소드
- 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
- 메소드
인증된 요청 (Credentialed Request)
세션id 가 저장되어있는 쿠키, Authorization 해더 토큰값 같은 자격 정보를 보낼 때 사용하는 방식
- 단순요청 조건을 만족하면
단순요청
으로 처리되고 아니면예비요청
으로 처리됨
제약 사항
해당 요청에서 서버측 해더에 이것들 지키지 않으면 CORS오류 뜸
Access-Control-Allow-Credentials
를 true로 설정Access-Control-Allow-Origin
,Access-Control-Allow-Methods
,Access-Control-Allow-Headers
에서*
사용불가
API 설정
Fetch
credentials
옵션을include
로 설정하기fetch("https://example.com:1234/users/login", { method: "POST", credentials: "include", // 자격 정보를 담겠다는 의미 })