웹개발 짜증유발자! CORS가 뭔가요?
📜 라디오 대본
얄코: 출근길 지하철에서 듣는 얄코 라디오!
얄코: 오늘의 주제는 CORS입니다.
얄코: 저는 얄팍한 개발자 얄코
미토: 미친토끼 미토에요
미토: 내가 이 CORS만 들으면 부아가 치밀어서 증말
미토: 이번 화에서 이 CORS란 놈을 좀 알고 가야겠어요
얄코: 웹 개발할 때 많은 초보 개발자분들을 당혹스럽게 하는게
얄코: 이 CORS, Cross Origin Resource Sharing이죠.
미토: 아니 내가 미친토끼 닷컴이라고 내 웹사이트를 만드는데
미토: 사이트에 서식지 정보를 넣으려고 네이버 지도 API에다가
미토: AJAX 요청을 보내가지고 뭘 받아오려고 할려면은
미토: 계속 뭐가 안 돼가지고 크롬에 개발자 도구 열어보니까
미토: 이 CORS가 어쩌고 하면서 시뻘겋게 떠 있는거에요
얄코: 그렇죠. 한 사이트에서 주소가 다른 서버로 요청을 보낼 때
얄코: 자주 접하게 되는 오류죠.
얄코: 주소가 '어쩌구' 닷컴인 웹사이트에서 URL이 '저쩌구' 닷컴인 서비스에
얄코: API로 정보를 받아오기 위해 '프론트에서' HTTP 요청을 보냈을 때
얄코: 미리 어떤 설정을 해 주지 않으면 CORS 문제로 막히게 돼요.
미토: 근데 이게 웃긴게, 다른걸로 테스트할 때는 다 되거든요?
미토: PostMan 같은걸로다가 똑같은 요청 보내보거나
미토: 스프링 같은거 백엔드에서 HTTP로 요청을 보내면 다 되가지고
미토: 아 이 URL로 GET 요청 보내면 되겠구나 하고 '웹사이트'에서 보내보면
미토: 죽어도 안 되는거에요, 맨날 이 CORS 어쩌구 하면서
미토: 왜 어디서는 되고 어디서는 안 되는거에요?
얄코: 그 '어디서'부터 알아야겠죠. 어디에서 보낸 요청이 CORS로 막히는가.
얄코: 웹사이트에서 AJAX을 요청 보냈을때마다 안 됐다고 했잖아요.
얄코: 그 말은 웹사이트를 여는 곳, 즉 크롬이나 엣지, 사파리 같은
얄코: 브라우저에서 일어나는 문제라는거죠. 프론트엔드에서요.
미토: 그러면 이 네이버 지도 같은 API 제공 서비스들이 내 크롬을 안 믿는거에요?
얄코: 그렇게 말하면 네이버는 억울한 게, 사실 이 CORS란 이유로 요청을 막는건
얄코: 바로 이 브라우저 쪽이에요.
미토: 아니, 그러면은 이 크롬이가 나를 못 믿는거란 말이에요?
미토: 뭔가 세게 뒤통수 맞은 느낌이네. 범인이 내 컴퓨터에 있었다는거 아녜요.
얄코: 크롬이 '미토씨'를 못 믿는게 아니라, '미토씨가 방문한 사이트'를 못 믿는거에요.
미토: 내가 개발하고 있는 이 사이트를 못 믿어가지고, 거기서 네이버 API에다가
미토: 요청을 못 보내게끄름 크롬이 막고 있는거다?
미토: 지가 뭔데 내가 하겠다는 걸 막고 그러는거에요?
얄코: 보통은 미토씨가 크롬에서 방문하는 사이트들은
얄코: 미토씨가 만든 게 아니잖아요.
미토: ...그렇죠. 남이 만든 사이트가 내 크롬에서 도는거지.
얄코: 이 CORS란 게 왜 있는건지부터 속 시원하게 알아볼게요.
얄코: 예시를 하나 들죠. 착한닷컴이라는 사이트가 있어요.
얄코: 미토씨도 여기에 가입해서 잘 쓰고 있다고 가정합니다.
얄코: 우리가 보통 어떤 사이트에 로그인을 하면
얄코: 다음에 접속했을 때 다시 아이디, 비번을 입력할 필요가 없도록
얄코: 로그인이 유지되고 있는 경우가 많잖아요.
얄코: 그게 어떤 원리로 그렇게 되는건지는 알고 계시죠?
미토: 예전에 쿠키, 세션, 캐시 다루는 영상에서 알려줬었죠.
미토: 내 브라우저에 토큰 등의 정보가 쿠키로 저장이 돼가지고
미토: 그거를 로그인 했던 사이트에 접속할 때 요청에다 실어보내면
미토: 그 사이트에서 이 쿠키를 보고 내가 거기 로그인이 돼 있다
미토: 이렇게 판단을 하는거 아녜요.
얄코: 맞아요. 즉, 미토씨가 착한닷컴에 로그인 해 있고
얄코: 그 상태가 유지되고 있다는 건 미토씨가 착한닷컴에 접속하거나
얄코: 그리로 API 요청 등을 보낼 때마다, 해당 요청들이
얄코: 미토씨로부터 왔음을 증명하기 위해 같이 보내지는 이 인증정보가
얄코: 미토씨의 크롬에 저장되어 있다는 얘기죠.
얄코: 자, 그런데 착한닷컴으로부터 미토씨의 정보를 빼내기 위해
얄코: 악당들이 나쁜닷컴이란 걸 만들었어요.
미토: 어떤 사이트 정보를 빼낼려구다가 다른 사이트를 만든다구요?
얄코: 어떤 속셈인건지 알려줄게요. 먼저 이 악당들은
얄코: 미토씨에게 링크가 담긴 메일을 거나 그럴듯한 게시물로 유인하거나 해서
얄코: 미토씨가 자신들이 만든 나쁜닷컴에 접속하도록 유도해요.
미토: 내가 나쁜닷컴에 접속을 한다는건 걔네가 만든 HTML, CSS
미토: 그리고 자바스크립트 코드가 내 브라우저에 받아진다는거고 오~
미토: 그렇구만, 이 나쁜닷컴에서 받아온 자바스크립트 코드로 갖다가
미토: 그놈들이 내 크롬한테 무슨 짓을 시킬 지 모르는거네요!
미토: 거기 내 착한닷컴 인증정보가 들어있는데!
얄코: 바로 그거에요. 착한닷컴으로부터 미토씨의 개인정보를 조회하는 요청에
얄코: 크롬에 저장된 미토씨의 착한닷컴 토큰을 실어서 착한닷컴에 보낸 다음
얄코: 그걸로 탈취한 정보를 나쁜닷컴 서버로 보내버릴 수 있는거죠.
미토: 오호라, 내 의지랑 상관없이 내 브라우저에서
미토: 거기 저장된 내 정보들을 가지고 악의적인 거를 할 수가 있는거고
미토: 그거 말고도 다른 API에다 뭐든 해괴한 짓을 할 수가 있는거기땜세
미토: 브라우저가 이런 것들을 방지를 하고 있었건거구만.
미토: 어떤 사이트에서 다른 사이트로는 요청이 못 가게끄름
미토: 이 CORS란 걸 가지고다가 말이에요
얄코: 정확히 말하자면, CORS는 그걸 막는게 아니라
얄코: 풀어주는 역할이구요. 요청을 막고 있는 건 SOP,
얄코: Same-Origin Policy가 하는거에요. '동일 출처 정책'이요.
미토: 동일 출처라는 거는 말 그대로 동일한 출처, URL끼리만
미토: API 등의 데이터 접근이 가능하도록 막는거고
미토: 개발자도구에 CORS 어쩌구 시뻘겋게 오류가 뜨는 거는
미토: '이게 되게 하려면 CORS란 거를 허용해주던가 해라'
미토: 이런 의미였던 거인 거였네요. 그럼 이 CORS가 정확히 뭐에요?
얄코: Cross-Origin Resource Sharing.
얄코: Cross-Origin이니까 Same-Origin, 동일 출처의 반대 개념이죠.
얄코: 말 그대로 다른 출처간에 리소스를 공유할 수 있도록 하는 걸 말해요.
얄코: 출처는 보내고 받는 각각의 위치 - 즉 웹사이트랑 API의 주소,
얄코: 리소스는 주고받아지는 데이터라고 생각하시면 돼요.
얄코: 즉 미친토끼닷컴과 네이버 지도 API, 이 서로 다른 출처끼리
얄코: 정보요청과 반환이 가능하도록 하는게 CORS라는거죠.
얄코: 사실 서로 다른 출처끼리 요청을 주고받는건 안 되는게 기본값이었어요.
얄코: 미친토끼닷컴에서 네이버 지도 API로 요청을 보내는 건
얄코: 원래 브라우저에서는 애초부터 금지되어 있던거란 얘기죠.
미토: 근게 그게 되게 할려고다가 CORS란걸 만든거란 얘긴 거인 거죠?
얄코: 맞아요. 웹 생태계가 다양해지면서 여러 서비스들간에
얄코: 보다 자유롭게 데이터가 주고받아질 필요가 생겼어요.
얄코: 그런데 다른 사이트간의 요청들을 브라우저가 막고 있으니까
얄코: 개발자들은 (요즘은 잘 안 보이지만) JSONP등의 방식으로
얄코: 이를 우회하는 꼼수들을 사용하기 시작했죠.
얄코: 그래서 이걸 합의된 출처들간에 합법적으로 허용해주기 위해
얄코: 어떤 기준을 충족시키면 리소스 공유가 되도록 만들어진 메커니즘이
얄코: 바로 이 CORS, 교차 출처 자원 공유 방식이에요.
미토: 그 조건이란게 뭔데요?
얄코: 간단해요. 요청을 받는 백엔드쪽에서 이걸 허락할 다른 출처들을
얄코: 미리 명시해두면 되는거죠.
얄코: 백엔드 서버를 프로그래밍할 때 쓰는 프레임워크들
얄코: 스프링이나 장고, Express 등의 문서를 살펴보면
얄코: CORS 옵션을 넣는 방법들이 쉽게 마련돼있어요.
얄코: 여기다 미친토끼닷컴 등 허용할 사이트들을 적어주면
얄코: 이제 거기서 지정한 사이트에서는 이 서버로 얼마든지
얄코: HTTP 요청들을 보낼 수 있는거에요.
얄코: 아무나 보내도 되는 요청의 경우, 일반적인 방법으로
얄코: 별표, 와일드카드를 적어넣으면 누구나 쓸 수 있게 되구요.
얄코: 당연히 '나쁜닷컴'은 안 들어가있을테니 거기는 막히겠죠.
얄코: 네이버 지도 API 등의 서비스들도 콘솔에 들어가보면
얄코: CORS를 허용해줄 주소들을 지정하는 페이지가 찾을 수 있을거에요.
미토: 여기다가 미친토끼닷컴을 등록하면 되는... 어 되네 돼 이제
미토: 이런거를 진작에 알았으면 이런 고생을 안 하는 건데 말이죠
얄코: SOP랑 CORS가 왜 있는건지 알았으니까
얄코: 이제 CORS에 대해서 조금 더 깊이 들어가볼게요.
얄코: 미친토끼닷컴에서 네이버 지도 API로 요청을 보내요.
얄코: 다른 출처로의 요청이니까, cross-origin 요청인거죠.
얄코: 브라우저은 이처럼 다른 출처끼리의 요청이 보내질 때는
얄코: 요청에 Origin이라는 header를 추가해요.
m 이 header가 뭔지 모르는 사람들 있을 것 같은데요.
얄코: 간단히 설명하자면, 데이터가 다른 곳으로 전송될 때
얄코: 데이터의 맨 앞쪽에 붙은 보충 정보라고 보면 돼요.
얄코: 받는 쪽의 IP 주소, 사용할 프로토콜이나 옵션 등이 담기는데
얄코: 우편으로 치자면 봉투에 적힌 내용이라고 생각할 수 있죠.
얄코: 여튼 이 header의 Origin 항목에는
얄코: 요청하는쪽의 scheme과 도메인, 그리고 포트가 담겨요.
얄코: 여기서 scheme이란, 요청할 자원에 접근할 방법
얄코: 이를테면 http, ftp, telnet 등을 말해요.
얄코: 프로토콜이라고도 하죠.
미토: https://미친토끼.com 으로 치면은
미토: https가 scheme, 미친토끼.com이 도메인, 그리고 안 붙었지만
미토: 만약 그 뒤에 :443 등이 달려이으면 그게 포트인거죠.
얄코: 네. 이 요청을 받은 네이버 지도 API 서버는 답장의 헤더에
얄코: 지정된 Access-Control-Allow-Origin 정보를 실어서 보내요.
얄코: 만약 미친토끼닷컴이 등록된 상태면 그 URL도 들어있겠죠.
미토: 그러면은 인제 크롬이 이 둘을 비교해가지고다가
미토: 오리진에 보낸거가 똑같이 있으면 오케이 해주는거네요?
얄코: 맞아요. Origin에서 보낸 출처값이 서버의 답장 헤더에 담긴
얄코: Access-Control-Allow-Origin에 똑같이 있으면
얄코: 안전한 요청으로 간주하고, 응답 데이터를 받아오게 되는거죠.
미토: 없으면은 그 시뻘건 에라 메세지를 갖다가 띄워주는거고 말이죠.
얄코: 그렇죠. 그리고 토큰 등 사용자 식별 정보가 담긴 요청에 대해서는
얄코: 보다 엄격해요. 일단 보내는 측에서는 요청의 옵션에
얄코: credentials 항목을 true로 세팅해야 하고
얄코: 받는쪽에서도, 아무 출처나 다 된다는 와일드카드가 아니라
얄코: 보내는 쪽의 출처 - 웹페이지 주소를 정확히 명시한 다음
얄코: Access-Control-Allow-Credentials 항목을 true로 맞춰줘야돼요.
미토: 브라우저에 저장된 쿠키가 나쁘게 쓰일 수 있는거니까
미토: 그거를 담아보내려면 양쪽이 보다 빡시게 조건을 갖춰놔야 되는거네요.
얄코: 맞아요. 그리고 방금 설명한 방식은 Simple request라고 해서
얄코: GET이나 POST 등 일정 조건의 요청들에 사용되는거구요
얄코: (그 조건들은 고정댓글 링크에서 확인하실 수 있어요.)
얄코: PUT이나 DELETE등 이와 다른 요청들은 본 요청을 보내기 전에
얄코: Preflight 요청이란 걸 먼저 보내서 본 요청이 안전한지 확인하고
얄코: 여기서 허락이 떨어져야 본격적으로 요청을 보낼 수 있어요.
얄코: 서버의 데이터에 영향을 줄 수 있는 요청들이기 때문에
얄코: 요청 자체를 보내기 전에 먼저 혀용 여부를 검증하는거죠.
미토: 정리하자면은 CORS에서 요청들은 두 종류
미토: 심플 리퀘스트랑 프리플라이티드 요청둘로 나뉘는데
미토: 심플 리퀘스트는 요청을 보내기는 다 보내는데
미토: 통과를 못하면 답장만 못 받아오는거고
미토: 후리플라이트를 하는거는 요청을 '보내는'것도 일단 허락을 받아야된다.
미토: 요청에 의해서 서버 데이터가 변경될 수 있는거라서.
미토: 근데 심플리퀘스트로 보내는 것들로도 받는쪽에서 신경 안 써놓으면
미토: 서버에 저장된 데이터에 변경이 가해질 수도 있는거잖아요?
얄코: 맞아요. 때문에 이 SOP만 믿을 게 아니라, 개발자 측에서도
얄코: 그런 것들에 다 대비를 해서 서버를 프로그래밍해야하는거죠.
미토: 안전벨트 맸다고 운전 막 하면 안 되는 것처럼요.
미토: 이 보안이란거는 아무리 신경을 써도 오바가 아닌거네요.
얄코: 오늘 이렇게 이 CORS란 것의 정체를 알아보는 시간을 가졌구요.
얄코: CORS의 동작에 대한 디테일한 부분들은 고정댓글 링크로
얄코: MDN에서 제공하는 한글 페이지에 들어가보시면
얄코: 친절한 설명들로 보다 자세히 확인하실 수 있습니다.
미토: 요즘 라디오로 만드는거 맛들려가지고 너무 날먹하는거 아녜요?
얄코: 장편강의 만들면서 중간중간 찍고 있는거에요.
얄코: 미토씨도 애 낳아가지고 육아하면서 코딩유튜브 해봐요.
미토: 저희 토끼들은요, 새끼를 까면 한 번에 열마리가 넘게도 나와요
얄코: 그 얘기를 하는 게 아니잖아요.
미토: 기네스북에 올라간 아는 형님은요, 1년에 4556마리를 낳아가지고
얄코: 얄코와 미토였습니다. 즐코하세요!