만족
CORS(Cross Origin Resource Sharing)의 이해 본문
CORS(Cross Origin Resource Sharing)의 이해
FrontEnd/Web Satisfaction 2022. 1. 1. 18:00MDN문서 내용을 바탕으로 설명할 것이다.
https://developer.mozilla.org/ko/docs/Web/HTTP/CORS#%EA%B8%B0%EB%8A%A5%EC%A0%81_%EA%B0%9C%EC%9A%94
CORS는 무엇이고, 왜 필요하며, 어떻게 CORS 문제를 해결하는지는 평소 개발할 때도 크게 도움이 되고,
웹 개발 직무 면접 시에도 자주 등장하는 만큼 반드시 알아두는 것이 좋다.
CORS는 무엇인가
교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제입니다.
웹 애플리케이션은 리소스가 자신의 출처(도메인, 프로토콜, 포트)와 다를 때 교차 출처 HTTP 요청을 실행합니다.
//mdn에서 CORS에 대해 묘사한 첫 문단
말 그대로 출처가 다른 곳(여기서 출처는 요청 대상 도메인)에 요청을 보낼 때,
요청의 종류에 따라 이 요청을 허용할지 판별하는 로직이다.
여기에서 domain-a.com이라는 웹 페이지에서 domain-a.com과 domain-b.com에 정보를 요청하여 페이지에 표시하고 있다.
domian-a.com에서 domain-b로 보내는 요청은 CORS에 의해 제어된다.
CORS 로직은 브라우저 내에 탑재되어 있으며,
브라우저에서 CORS가 허용되지 않는 대상에 요청을 보낼 경우 그 요청을 실패로 처리하게 한다.
그렇다면 왜 출처가 다른 요청에 대해 더 엄격한 기준을 적용하는 것일까?
CORS는 왜 추가되었는가?
클라이언트의 보안을 위한 로직이다.
CORS는 XSS(스크립트 삽입 공격), CSRF(사이트간 요청 위조) 공격을 방지할 수 있는데,
XSS의 경우 원본 출처에서 다른 출처(공격자의 서버)로 개인 정보를 탈취하는 공격이고,
CSRF의 경우 다른 출처에서 원본 출처에 정보를 보내 조작하는 공격이므로,
교차 출처에 대해 엄격한 기준을 적용한다면 위 두 공격에 대해 비교적 자유로워질 수 있다.
모던 브라우저, 심지어는 IE11에도 적용(IE의 경우 포트는 비교하지 않는다)되어 있으므로,
백엔드 개발자와 프론트엔드 개발자 모두 알아두어야 하는 개념이다.
CORS 시나리오: 단순 요청
단순 요청의 정의는 이곳에서 확인할 수 있다.
클라이언트가 GET메서드로 서버에 요청하고 있다.
요청을 보낼 때 브라우저가 자동으로 Origin헤더를 추가한다.
이 Origin값을 보고 서버가 응답을 거부할 수도 있고,
응답을 보낸다고 하더라도 Access-Control-Allow-Origin헤더에 명시되지 않은 출처(Origin)이라면
클라이언트의 브라우저에서 응답을 받지 못하게 될 수도 있다.
이 경우 서버가 Access-Control-Allow-Origin헤더에 *(전체)를 명시했으므로,
응답을 정상적으로 받을 수 있다.
만약 Access-Control-Allow-Origin: https://bar.example 처럼 설정되었다면,
출처(Origin)이 https://foo.exmple 이였으므로 이 요청은 브라우저에 의해 가로막힌다.
CORS 시나리오: 프리플라이트 요청
처음 이 요청을 맞닥뜨렸을 때 당황한 기억이 난다.
서버의 상태를 변화시키는 요청(계정 삭제, 회원 정보 변경 등)은
단순 조회(GET)같은 동작보다 더 조심스럽게 다루어야 한다.
단순 요청에서는 CORS를 위반하더라도 서버에 요청이 들어간 이후 Access-Control-Allow-Origin의 값에 따라
브라우저가 응답을 처리할지 말지 결정하는 구조였지만,
서버의 상태를 변화시키는 요청의 경우, 요청 자체가 유효한지 먼저 검사할 필요가 있다.
단순 요청처럼 다뤄질 경우 응답만 받지 못할 뿐 요청은 이미 서버에서 처리되어버리기 때문이다.
서버의 상태를 변화시키는 요청이 전송되기 전,
브라우저에서 먼저 Preflight request를 발송하여 이 요청이 유효한 요청인지를 먼저 검사한다.
(이 과정은 스크립트에서 명시하지 않더라도 브라우저에서 자동으로 추가하는 로직이다)
Preflight request에서 OPTION 메서드를 이용해 출처, 메서드, 헤더값에 대해 유효한 요청인지를 서버에 묻는다.
만약 허용된 타입의 요청이라면 Main Request 단계로 이동하여 실제 요청을 보내고 응답을 받을 수 있다.
그렇지 않다면, Preflight가 끝나고 CORS오류가 발생해 Main Request에 도달하지 못하게 된다.
정리하자면 실제 요청을 보내기 전에 Preflight를 통해 서버에게 '이 요청을 보내도 되겠습니까?'를 허락받는 것이다.
CORS 오류의 해결
CORS 오류가 떴다는 것은 서버가 허용하지 않은 출처, 메서드, 헤더값을 사용했다는 것이다.
따라서 두 가지 측면에서 해결법이 존재한다.
먼저 클라이언트 측에서는 서버가 허용하는 출처, 메서드, 헤더값을 사용해야만 한다.
CORS 오류가 발생한 요청을 찾아 response header를 살펴보면 서버가 어떤 값들을 허용하는지를 알 수 있다.
서버의 경우 Access-Control-Allow-Origin 헤더를 통해 허용할 도메인을 지정해줄 수 있다.
단 이 때는 모두 허용하거나(*), 한 개의 도메인(https://foo.example)만 허용할 수 있다.
추가로 Access-Control-Allow-Methods, Access-Control-Allow-Headers 등을 통해
출처뿐만 아니라 허용되는 메서드, 헤더값 등에 대해서도 정의할 수 있다.
더 많은 서버의 응답 헤더에 대해서는 아래 링크를 참조하자.
https://developer.mozilla.org/ko/docs/Web/HTTP/CORS#the_http_response_headers
CORS 오류의 해결: 개발 도메인
localhost와 같은 도메인에서 개발할 때 CORS를 처리할 수 있는 방법에 대해 소개한다.
물론 Access-Control-Allow-Origin을 *로 설정할 수도 있겠지만,
이것이 의도한 동작이 아니라면 위에서 말한 CORS의 등장 배경에서 소개한 위험성이 다시 찾아온다는 것이므로 다른 방법을 사용해야 한다.
CORS로직은 브라우저에 탑재되었다고 소개했는데, 개발시에는 이 기능을 잠시 무력화시키면 (개발에 사용중인 컴퓨터에 한해)
서버의 상태를 변화시키지 않고 정상적으로 응답을 받아볼 수 있다.
물론 이 확장 프로그램을 사용중인 사람에 한해서만 CORS가 무력화되는 것이기 때문에
다른 사용자들은 여전히 CORS에 시달릴 것이며, 서버가 Origin을 검사해 요청을 거부하는 로직이 있을 경우 실패한다.
어디까지나 개발의 편의성을 위해서만 사용하자.
'FrontEnd > Web' 카테고리의 다른 글
[Web] 이미지 크기 지정과 애드센스 최적화로 CLS(Cumulative Layout Shift) 수치 낮추기 (0) | 2023.03.01 |
---|---|
[Javascript] 브라우저에서 import/export 사용하기 (0) | 2022.01.31 |
[Javascript] 네트워크 끊김/연결 감지 (0) | 2020.11.04 |
[Javascript] REST API 호출을 위한 라이브러리, axios (2) | 2020.01.19 |
[Javascript] Cookie (0) | 2018.07.05 |