모든 웹 관리자, 서버 개발자, 프론트엔드 개발자를 위한 필독서 CORS : developer.mozilla.org/ko/docs/Web/HTTP/CORS
cors는 쉽게 말하자면 악의를 가진 해커로부터 인터넷을 보하하기 위해 만들어졌다.
node.js의 http 모듈을 이용하여 웹 서버를 만드는 시간을 가졌다. HTTP 모듈, HTTP 트랜잭션 해부라는 Node의 공식 가이드를 참고 하여, 페어와 상의하며 코드를 짰었다. 어느정도 완성했다고 생각하고, nodemon이라는 편리한 API를 통해 테스트를 거쳤는데 콘솔 로그에서는 아래와 같은 경고창을 띄어 어지럽게 만들어줬다.
Access to fetch at 'http://localhost:5000/line' from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: 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.
cors에 대해 제대로 공부하지 않고 접근부터 했기 때문에 이 오류를 보고서도 쉽사리 해석을 하지 못했었다. 출처가 왜 'null'일까? preflight는 또뭐고, 왜 CORS는 disabled인지.. 모르기 때문에 직접 찾아보고 기록을 하기로 했다.
교차출처 리소스 공유란?
교차출처 리소스 공유(Cross-Origin Resouce Sharign, CORS)는 한 출처에서 실행중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에서 알려주는 체제이다. MDN 설명은 너무 어렵게 기술되어 있어 이해하기가 쉽지가 않았다.
여기서 말하는 교차 출처를 알기 위해 출처(Origin)에 대해 파해쳐 보자. 우선 특정 웹페이지의 상단의 주소를 복사하거나 콘솔 로그를 찍어보면 아래의 주소처럼 나올것이다(port는 제외). 이런 URL들은 여러개의 구성요소로 이루어져있다.
console.log(location.origin);
VM124:1 https://www.tistory.com
[Protocol] [Host] [Port]
https:// www.tistory.com :443
HTTP : 80
HTTPS: 443
여기서 출처는 프로토콜(Protocol, [schema]), 호스트(Host), 포트(Port) 번호를 모두 합친 것을 의미한다. 서버의 위치를 찾아가기 위해 필요한 가장 기본적인 것들을 합쳐놓은 것이다. 출처 내의 포트 번호는 각 웹에서 사용하는 HTTP, HTTPS 프로토콜 기본 포트가 정해져 있기 때문에 생략이 가능하다.
교차(Cross) 출처
교차(cross)는 그냥 쉽게 생각해서 다른 출처라고 생각하면된다. 동일 출처의 경우 단 3가지 부품(URL)들이 완전히 일치해야한다. 두 개의 출처 부품들의 프로토콜(Protocol), 호스트(Host), 포트(Port)를 각 브라우저상에서 정해진 비교 로직을 통해 판단한다. 교차 검증으로 브라우저 상에서 CORS 정책을 위반한 경우 브라우저는 해당 응답을 사용하지 않고 버리게 됨과 동시에, 에러를 로그에 띄우게 된다.
어떤 요청이 CORS를 사용할까?
- XMLHttpRequest와 Fetch API 호출(domainA출처에서 XML과 Fetch를 사용해서 DominB/data.json 을 요청하는 경우)
- 웹 폰트(CSS내의 @font-face에서 교차 도메인폰트 사용 시)
- WebGL 텍스쳐
- drawImage()를 사용해 캔버스에 그린 이미지/비디오 프레임
- 이미지로부터 추출하는 CSS Shapes
Preflight Request
브라우저가 우리가 보낼 요청을 보내기 전에 미리 보내는 요청을 Preflight라고 부른다. 이 예비 요청에는 HTTP 메소드중에 OPTIONS 메소드가 사용된다. 즉, 원래의 요청을 보내기 전에 브라우저 스스로 이 요청을 보내는 것이 안전한지 확인하는 방법이다.
브라우저는 본 요청을 보내기 전 예비 요청을 먼저 보내고, 요청의 유효성을 검사한다.
어떻게 사용할까?
CORS에서, OPTIONS 메소드를 통해 preflight request(사전전달 요청) 사전 요청을 보내 서버가 데이터를 보내도 되는지에 대한 응답을 준다.
OPTIONS /resources/post-here/ HTTP/1.1
Host: bar.other
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
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
만약 서버가 허용한다면, 응답 헤더에 HTTPHeader("Access-Control-Allow-Methods")라고 나타나게된다. 이 헤
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
동일 출처 정책(Same-Origin Policy, SOP)
웹 생태계에는 교차 출처의 리소스요청을 제한하는 것과 관련된 두가지 정책이 존재한다. 한가지는 교차출처 자원공유(Cross-Origin Resource Sharing, CORS), 그리고 동일 출처 정책(Same-Origin Policy, SOP)이다.
참고자료
'FE BE 개발 메모장 > Client Server Architecture' 카테고리의 다른 글
쿠키(Cookie) (0) | 2021.03.05 |
---|---|
HTTPS (0) | 2021.03.04 |
REST API에 대해 이해하기 (0) | 2021.02.05 |
HTTP 메세지 (0) | 2021.02.05 |
클라이언트 서버 통신과 HTTP API (0) | 2021.02.03 |