배워서 남주는 개발자 :)

Web

CORS 는 무엇일까? CORS (교차 출처 자원 공유 방식)에 대한 정리!

핏짜보이 2022. 4. 10. 11:37
반응형

<목차>

들어가면서

1. CORS에러는 어디서 발생하는 것일까?

2. CORS의 역할 (1)

3. CORS의 역할 (2)

4. CORS의 조건

5. CORS에서 보내는 요청의 종류

 

 

 

들어가면서

의미적으로 살펴보면 CORS는 Cross Origin Resource Sharing입니다.

 

예를 들어서 웹사이트에 네이버지도 API에다가 AJAX 요청을 보내서 특정한 데이터를 받아오려고 하면, CORS 와 관련된 오류가 발생하는 경우를 종종 볼 수 있습니다.

 

한 사이트에서 주소가 다른 서버요청을 보낼 때 자주 접하게 되는 오류입니다.

 

주소가 AAA닷컴인 웹사이트에서 URL이 BBB닷컴인 서비스에 API로 정보를 받아오기 위해 '프론트'에서 HTTP요청을 보냈을 때

미리 특정한 설정을 해주지 않으면 CORS 문제로 막히게 되는 것입니다.

 


1. CORS에러는 어디서 발생하는 것일까?

특히 로컬이나 다른 환경에서는 가능한데, 웹 브라우저에서 요청을 보낼 때에 CORS와 관련된 오류들이 발생합니다.

 

여기서 중요한 점은 '어디서' 보낸 요청은 되고 안되는지 기준을 명확히 알아야 합니다.

 

웹사이트를 여는 곳, 즉 크롬, 엣지, 사파리 같은 브라우저(프론트엔드)에서 일어나는 문제라는 것입니다.

 

CORS라는 이유로 요청을 막는 주체는 브라우저입니다. 

다시 말해 우리가 사용하는 크롬이 '내가 방문한 사이트'믿지 못해서 에러가 발생하는 것입니다.

 

보통 우리가 크롬에서 방문하는 사이트들은 우리가 만든 것이 아닙니다.

남이 만든 사이트들이 내 크롬에서 실행되는 것입니다. 

 

이것을 이해하기 위해서 CORS가 존재하는 이유를 알아볼 필요가 있습니다.

 


2. CORS의 역할 (1)

예를 들어 우리가 구글이라는 사이트에 회원가입을 하고 잘 사용을 하고 있다고 가정합니다.

우리가 보통 어떤 사이트에 로그인을 하면 다음에 접속했을 때 다시 아이디, 비밀번호를 입력할 필요가 없도록

로그인이 유지되고 있는 경우가 많이 있습니다.

 

간단히 말하면, 내 브라우저에 토큰 등의 정보가 쿠키로 저장되고, 이것을 로그인 했던 사이트에 접속할 때마다 요청에 실어보내면 

해당 사이트에서 이 쿠키를 보고 내가 해당 사이트에 로그인이 되어있다고 판단하고 유지가 되는 것입니다.

 

우리가 구글에 로그인 되어있고, 그 상태가 유지되고 있다는 건 우리가 구글에 접속하거나 구글에 API요청을 보낼때마다,

해당 요청들이 나에게서 왔음을 증명하기 위해 보내는 이 인증정보가 우리의 크롬(브라우저)에 저장되어 있다는 의미입니다.

 

그런데 나쁜 사람들이 구글로부터 우리의 정보를 빼내기 위해 '쿠글'이라는 가짜 사이트를 만들었다고 가정합시다.

여기서 어떤 사이트의 정보를 빼내려고 다른 사이트를 만든다는 말이 이해되시나요??

 

먼저 이 나쁜 사람들은 우리에게 정보를 빼내기 위해서 해당 사이트로 연결된 링크가 담긴 메일을 보내거나 그럴듯한 게시물로 유인해서 

우리가 그들이 만든 '쿠글'이라는 사이트에 접속하도록 유인합니다.

 

우리가 '쿠글'이라는 사이트에 접속한다는 것은, 그들이 만든 HTML, CSS, JS코드가 우리의 브라우저에 받아진다는 것을 의미합니다.

 

해당 사이트에서 받아온 JS 코드로 나쁜 사람들이 내 크롬에 어떤 짓을 시킬지 모르는 것입니다.

크롬에 '구글'에 대한 우리의 인증정보가 들어있는 데 말이죠!

 

'구글'로부터 우리의 개인정보를 조회하는 요청에 크롬에 저장된 우리의 구글 토큰을 실어서 구글에 보낸다음

그걸로 탈취한 정보를 '쿠글'의 서버로 보내버릴 수 있는 것입니다!!!

 

즉, 나의 의지랑 상관없이 내 브라우저에서 여기에 저장된 내 정보를 가지고 악의적인 행동을 할 수 있고,

이것 말고도 다른 API에 알 수 없는 짓을 할수 있기 때문에 브라우저가 이런 것들을 방지하고 있는 것입니다.

 

어떤 사이트에서 다른 사이트로는 요청이 못가게끔 CORS라는 것을 가지고 방지하고 있었던 것입니다.

 


3. CORS의 역할 (2)

정확히 말하면 CORS는 그것을 막는 것이 아니라, 풀어주는 역할입니다.

요청을 막고 있는 것SOP (Same-Origin Policy)라는 '동일 출처 정책' 입니다.

동일 출처라는 말은 말그대로 동일한 출처나 URL끼리만 API 등의 데이터 접근이 가능하도록 막는 것이고 

개발자 도구에 보이는 CORS 에러는 '이것이 가능하게 하려면 CORS라는 것을 허용해주세요!' 라는 의미였던 것입니다.

 

CORS는 Cross-Origin Resource Sharing, 즉 위에서 말한 Same-Origin의 동일 출처의 반대 개념입니다.

말 그대로 다른 출처간에 리소스를 공유할 수 있도록 하는 것을 말합니다.

출처는 보내고 받는 각각의 위치, 즉 웹사이트와 API의 주소,

리소스는 주고 받아지는 데이터라고 생각하시면 됩니다.

 

즉, 우리가 만든 웹사이트와 구글의 지도 API, 서로 다른 출처끼리 정보요청과 반환이 가능하도록 하는것이 CORS라는 것입니다.

사실 서로 다른 출처끼리 요청을 주고 받는 것이 안되는게 기본 값이었습니다.

우리가 만든 웹사이트에서 구글의 지도 API로 요청을 보내는 건 원래 브라우저에서는 애초부터 금지되어있단 이야기 입니다.

 

 웹 생태계가 다양해지면서 여러 서비스들 간에 보다 자유롭게 데이터가 주고 받아질 필요가 생겼습니다. 

그런데 다른 사이트 간의 요청들을 브라우저가 막고 있으니까

개발자들은 JSONP 등의 방식으로 이를 우회하는 꼼수를 사용하기 시작했습니다.

 

그래서 이 과정을 합의된 출처들 간에 합법적으로 허용해주기 위해 어떤 기준을 충족시키면

리소스가 공유되도록 만들어진 메커니즘이 바로 CORS, 교차 출처 자원 공유 방식입니다.

 


4. CORS의 조건

여기서 말하는 충족시켜야 하는 기준은 무엇일까요?

바로 요청을 받는 백엔드 쪽에서 이것을 허락할 다른 출처들을 미리 명시해주면 되는 것입니다.

 

 

백엔드 서버를 프로그래밍할 때 쓰는 프레임워크(Spring, Django, Express등)의 문서를 살펴보면

CORS 옵션을 넣는 방법들이 나와있습니다.

 

여기에 우리가 만든 웹사이트등의 허용할 사이트들을 적어주면 이제 이렇게 지정한 사이트에서는 해당 서버로 얼마든지 HTTP 요청을 보낼 수 있는 것입니다.

 

아무나 보내도 되는 요청의 경우, 일반적인 방법으로 별표, 와일드카드를 적으면 누구나 쓸 수 있게 됩니다.

당연히 나쁜 사람들이 만든 '쿠글'같은 경우는 포함되어 있지 않으니까 해당 사이트는 막힐 것입니다.

 

구글 지도 API 등의 서비스들에도 콘솔에 들어가보면 CORS를 허용해줄 주소들을 지정하는 페이지가 있습니다.

해당 페이지에서 우리가 만든 웹사이트를 추가해주면 데이터 정보 교환이 가능합니다.

 

브라우저는 이처럼 다른 출처끼리의 요청이 보내질 때요청에 Origin이라는 header를 추가합니다.

여기서 말하는 header는 데이터가 다른 곳으로 전송될 때, 데이터의 맨 앞쪽에 붙은 보충 정보입니다.

여기에는 받는 쪽의 IP주소, 사용할 프로토콜이나 옵션 등이 담기는데,

우편으로 생각해보면 봉투에 적힌 내용이라고 이해하면 이해가 쉬울 것입니다.

 

header의 Origin항목에는 요청하는 쪽의 scheme과 도메인, 그리고 포트가 담깁니다. 

여기서 scheme이란 요청할 자원에 접근할 방법(예를 들어 http, ftp, telnet등 프로토콜이라고도 합니다.)을 말합니다.

 

//예를 들어서 주소가 아래와 같다면
https://jasonCoding.com : 8080
//https가 scheme, jasonCoding.com이 도메인, 그리고 뒤에 붙은 : 8080이 포트번호 입니다.

이 요청을 받은 구글 지도 API 서버는 답장의 header 부분에 지정된 Access-Control-Allow-Origin 정보를 실어서 보냅니다.

만약 우리의 웹사이트가 등록된 상태이면 해당 URL도 들어있을 것입니다.

 

그럼 이제 크롬이 이 둘을 비교해서 Origin에 보낸 정보가 똑같이 존재하면 허용을 해주는 방식입니다.

다시말해, Origin에서 보낸 출처값이 서버의 답장 헤더에 담긴 Access-Control-Allow-Origin에 똑같이 존재한다면 

안전한 요청으로 간주하고, 응답 데이터를 받아오게 되는 것입니다.

 


5. CORS에서 보내는 요청의 종류

그리고 토큰 등의 사용자 식별 정보가 담긴 요청에 대해서는 보다 엄격하게 적용합니다.

먼저 보내는 측에서는 요청의 옵션에 'credentials'라는 항목을 true로 세팅해야 하고, 

받는 쪽에서도 아무 출처나 다 된다는 와일드 카드가 아니라 보내는 쪽의 출처-웹사이트 주소를 정확히 명시한 다음 

Access-Control-Allow-Credentials 항목을 true로 맞춰줘야 합니다.

 

브라우저에 저장된 쿠키가 나쁘게 사용될 수 있기 때문에 이것을 담아서 보내려면

양쪽 모두에서 보다 엄격하게 조건을 갖춰야 하는 것입니다.

 

그리고 위에서 말한 방식은 Simple request 라고 해서 GET이나 POST등 일정 조건의 요청들에 사용되는 방식입니다.

 

PUT이나 DELETE등 이와 다른 요청들은 본 요청을 보내기 전에 Preflight 요청이라는 것을 먼저 보내서 본 요청이 안전한지 확인하고 

여기서 허용이 되어야 본격적으로 요청을 보낼 수 있습니다.

이런 방식들은 서버의 데이터에 영향을 줄 수 있는 요청들이기 때문에 요청 자체를 보내기 전에 먼저 허용 여부를 검증하면서 더욱 엄격하게 적용되는 것입니다.

 

정리하자면 CORS에서 보내는 요청은 두 종류가 있습니다.

1) Simple request - GET/ POST 방식

요청은 다 보내기는 하지만, 통과를 못하면 res만 못 받아오는 방식입니다.

 

2) Preflight request - PUT/ DELETE 방식

'요청을 보내는 것'부터 먼저 허락을 받아야 요청을 보낼 수 있는 방식입니다.

요청에 의해서 서버 데이터가 변경될 수 있는 것이기 때문입니다.

 


 

그런데 Simple request로 보내는 요청도 받는 쪽에서 신경 쓰지 않으면, 서버에 저장된 데이터에 변경이 가해질 수도 있습니다.

그래서 SOP만 믿을 것이 아니라, 개발자들도 이런 것들으 생각하고 대비해서 서버를 프로그래밍 해야합니다. 

 

오늘은 이렇게 CORS에 대해서 알아보았습니다.

질문과 지적은 댓글로 환영합니다.

오늘도 모두 즐코하세요!! :)

 

 

 

 

참고사이트

https://www.youtube.com/watch?v=bW31xiNB8Nc 

https://developer.mozilla.org/ko/docs/Web/HTTP/CORS

https://en.wikipedia.org/wiki/Cross-origin_resource_sharing

https://cchoimin.tistory.com/entry/JavaScript-CORS란

 

 

 

 

728x90