CORS가 허용되거나 차단되는 과정은 이미 자료가 충분히 많다.
이 글에선 사용 목적과 구현 방식, 그 이유, 한계를 알아본다.
CORS: Cross-Origin Resource Sharing
CORS는 교차(서로 다른) 출처 간 자원 공유를 위한 메커니즘이다.
중요한 점 하나는 자원 공유를 틀어막기 위한 기술이 아니라, 안전하게 풀기 위한 기술이라는 것.
브라우저는 사용자의 인터넷 환경을 따르기 때문에 다른 출처의 자원에 접근하는 것만으로도 위험할 수 있다.
따라서 브라우저는 Same-Origin Policy를 사용해 스크립트가 다른 출처의 리소스를 접근하지 못하게 막는다.
(사실 스크립트 외에도 몇 가지 더 있지만, 여기서는 스크립트만 다룬다)
구체적인 이야기는 뒤에서 해보자.
그냥 다 접근할 수 있게 열어두면 안될까?
CORS가 존재하지 않는다고 가정해보자.
악의적인 사이트 A는 사용자의 브라우저로 B사이트의 자원을 요청하고, 그 결과를 다시 전송받는 스크립트를 탑재했다.
(1) A 사이트에 접속하면, 클라이언트는 스크립트에 의해 (2) B 사이트에 접근한다.
(3) 스크립트는 (2)의 결과를 A 서버로 전송한다.
이 행위는 두 가지 입장에서 볼 수 있다.
이렇게 악의적인 요청은 어플리케이션에 따라서 큰 손해를 일으킬 수도 있다.
그래서 브라우저의 CORS 정책은 기본 Same-Origin으로 설정되어 있다.
같은 출처간의 접근만 허용한다.
‘같은 출처’라 함은, 호스트와 포트까지 같은 것을 의미한다.
반대로 서버에서 허용을 명시하지 않으면 다른 출처에서는 접근이 불가하다.
ex)
localhost:8080
(웹 페이지) →localhost:9090
(서버)
서버가 별도로 명시하지 않았다면, 접근이 불가하다.
현대의 웹 어플리케이션은 웹 클라이언트와 서버가 다른 주소에 있는 경우도 많다.
따라서 클라이언트는 접속한 사이트와 다른 주소로 요청을 보내야 한다.
이 경우 서버가 특정한 클라이언트(들)에 한해 요청을 허용해주기 위한 설정을 한다.
다음처럼 응답 헤더에 허용할 출처, 메서드 등을 적어주는 방식이다:
이를 해석해보면 다음과 같다
https://localhost:443
에서도, https://naver.com
에서도, http://localhost:8080
에서도 이 리소스에 접근이 가능하다.다시 말하지만, CORS는 무조건 틀어막는 것이 아니라 다른 출처에 안전하게 접근하기 위한 방법이다.
이대로라면 그렇다.
이미 요청이 들어갔고, 그 응답으로 Access-Control-Allow-Origin
등 서버의 CORS 설정이 응답됐다.
서버는 소 잃고 외양간을 고쳐달라고 하는 셈이다.
이런 일을 막기 위해 브라우저는 스크립트를 통해 다른 출처에 보내는 요청을 조금 다르게 관리한다.
본 요청을 보내기 전, Preflight Request를 보낸다.
Preflight Request는 OPTIONS
메서드 및 특정 헤더가 설정되어 날아간다.
이 요청은 GET, POST, DELETE 등 일반적인 Method와 구분되므로, 서버는 CORS 설정을 포함시켜 적절한 응답을 내려줄 수 있다.
그 응답이 바로 이전에 봤던 응답이다.
브라우저는 Preflight Request의 응답을 해석한 후, 문제없다고 판단한 후에서야 비로소 본 요청을 보낸다.
CORS는 브라우저 단(클라이언트 측)에서 구현된 행위다.
따라서 CORS 정책을 지원하지 않거나 취약점이 있는 브라우저, 혹은 별도 클라이언트를 사용하면 Same-Origin이 아니라도 얼마든지 요청을 보내고 응답받을 수 있다.
CORS는 부가적인 보안 정책일 뿐, 악의적인 행위의 원천 차단은 불가능하다.
우테코 동영상 서버에는 연극 영상이 있고, LMS에 탑재하기 위해 리소스를 공개했다.
하지만 연극 영상은 극비이기 때문에 LMS 외부로 노출되어선 안된다.
CORS 응답 헤더에 Access-Control-Allow-Origin: https://techcourse.woowahan.com
을 싣는것으로 목적을 달성할 수 있을까?
당연하게도 답은 ‘도움되지 않는다’이다.
CORS의 Same-Origin Policy는 웹 브라우저에서 사용하는 정책일 뿐이다.
서버가 Preflight Request에 응답하는 내용은 단지 희망사항일 뿐이며, 클라이언트는 얼마든지 다르게 처리할 수 있다.
따라서 외부인도 별도의 클라이언트나 웹 페이지를 조금 조작하는 것만으로 ‘극비 동영상’에 접근할 수 있다.
이 목적을 위해선 다른 기술을 사용해야 한다.
마찬가지로 우테코 영상 서버에 연극 영상이 있다고 하자.
연극 영상의 리소스를 /secret-video.mov
로 공개하고, CORS Origin을 https://techcourse.woowahan.com
으로 한정했다.
LMS 페이지에 <video src="https://video-server/2023/secret-video.mov"/>
를 삽입한다.
연극이 LMS 페이지에 공개됐다.
일반적인 환경에서는 이 태그를 다른 출처에서 사용할 순 없겠지?
만만의 콩떡이다.
video, img,script 등 HTML 태그의 src는 CORS와 관계없다.
다시 말하지만, CORS의 Same-Origin Policy는 ‘스크립트’가 다른 출처에 접근하는 것을 막는다.
따라서 HTML 태그는 관리 대상이 아니며, 저 태그를 어디에 삽입해도 동영상이 잘 로드된다.
이렇게 만든 이유는 아쉽게도 아직 알아내지 못했다.
(누가 알려주세요..!)
본인이 추측하기로는 다음과 같다.
오히려 이것들에도 CORS를 적용하면, ‘미디어 표시’라는 웹의 핵심 기능에 큰 제약이 생긴다.
따라서 보안 위협을 막는 효과는 미미하고, 제약사항은 커지니 하나를 포기하거나, 다른 방식으로 보완하지 않았을까 추측한다.
이 글은 이해를 돕기 위해 생략된 내용들이 많다.
잘 읽었습니다~