서론

프론트앤드와 서버를 분리한 후, Web API를 통하여 통신을 하다보면, 필연적으로 마주치는 것이 CORS 오류이다.

이 오류를 여러 번 마주쳐서, 나는 이 문제를 이해하고, 문제를 해결했다고 생각했지만, 최근에 CORS에 관한 질문을 받고, 대답하는 중, 내가 이해를 제대로 하지 못했구나!라고 생각하며 좀 더 깊게? 공부해보기로 했다.

 

그리고 앞으로는 여러 개념들을 깊게 공부해보며, 개인 Notion에 정리해놓은 것들을 블로그에 깔끔하게 정리해보려 한다.

 

SOP( Same-Origin Policy )란?

MDN에서는 이렇게 설명한다.

 

동일 출처 정책(same-origin policy)은 어떤 출처에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한하는 중요한 보안 방식입니다. 동일 출처 정책은 잠재적으로 해로울 수 있는 문서를 분리함으로써 공격받을 수 있는 경로를 줄여줍니다.

 

간단하게 설명하자면 a.com이라는 사이트에서는 a.com에서만 정보를 가져올 수 있다는 것이다. 즉 프론트 서버는 a.com으로, 백앤드 서버는 b.com으로 분리하면 안되고, 둘 다 a.com에 존재해야 데이터를 주고 받을 수 있다는 것이다.

 

그럼 같은 출처(origin)은 어디까지가 같은 출처인가? 

MDN에서는 다시 이렇게 말한다.

 

두 URL의 프로토콜, 포트(명시한 경우), 호스트가 모두 같아야 동일한 출처라고 말합니다. "스킴/호스트/포트튜플"이나 그냥 "튜플"(2개 이상의 요소가 전체를 구성하는 집합)이라고 하기도 합니다.

 

 URL http://store.company.com/dir/page.html의 출처를 기준으로 친절하게 표까지 작성해주었다.

URL 결과 이유
http://store.company.com/dir2/other.html 성공 경로만 다름
http://store.company.com/dir/inner/another.html 성공 경로만 다름
https://store.company.com/secure.html 실패 프로토콜 다름
http://store.company.com:81/dir/etc.html 실패 포트 다름 (http://는 80이 기본값)
http://news.company.com/dir/other.html 실패 호스트 다름

 

즉 프로토콜 ( http, https ), 포트( :81, :3000 등), 호스트 ( www.tistory.com  )까지 같아야하고, 이 중 하나라도 다르면 같은 출처( Same-Origin) 으로 간주하지 않는다는 것이다.

 

이 문제를 해결하기 위하여 다양한 방법이 있고, MDN에 이 방법들이 적혀있다.

여러 방법이 있지만, 그 중 가장 안전하고 권장하는 방법이 바로 CORS이다.

 

CORS ( Cross-Origin Resource Sharing ) 란?

진리의 MDN에서는 이렇게 설명한다.

 

교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제입니다. 웹 애플리케이션은 리소스가 자신의 출처(도메인, 프로토콜, 포트)와 다를 때 교차 출처 HTTP 요청을 실행합니다.

 

즉 간단하게 말하면, HTTP 헤더에 정보를 추가하여, 다른 Origin끼리도 데이터를 주고 받을 수 있게 한다!라는 것이다.

 

a.com에서 b.com의 데이터를 요청한다면,

클라이언트에서 서버로 요청할 때 http header에 { Origin : a.com } 이렇게 요청하는 곳의 출처를 넣고, 

서버에서 클라이언트로 응답할 때는 { Access-Control-Allow-Origin : 허용할 주소 } 이렇게 응답을 보낸다.

 

그리고 만약 내가 요청한 주소가 허용할 주소에 포함되어 있다면, 데이터를 받아서 화면에 뿌려준다.

 

그렇지만 반대로 요청한 주소가 허용할 주소에 포함되어 있지 않다면, CORS 오류가 발생한다.

 

CORS 오류 해결 방법

이 문제를 해결하기 위해서는 서버 측에서 응답할 때 http header 내에 있는 { Access-Control-Allow-Origin : 허용할 주소 }에 a.com을 넣어주면 CORS 오류는 발생하지 않게 된다. 

 

혹은 어느 사이트에서 요청할지 모르니, { Access-Control-Allow-Origin : * } 로, 모든 주소를 허용하면 편하게 해결할 수 있다. 물론 이렇게 된다면 보안상 문제가 생길 수 있다.

만약 내가 서버를 건들일 수 없다면, 이 문제는 브라우저에서 막아서 발생하는 문제이므로, 프록시 서버를 하나 만들어서, 프록시 서버에서 정보를 받아온 후, 클라이언트에  { Access-Control-Allow-Origin : 허용할 주소 }를 허용하여 문제를 해결할 수 있다.

 

이 부분은 시간이 되면 그림과 함께 자세히 다루어보려고 한다.

그리고 클라이언트 쪽에서 문제를 해결하는 방법을 찾아보려한다.

 

CORS의 보안 문제?? 어디가??

사실 이 윗부분은 CORS를 구글에 검색하면 나오는 보편적인 내용이다. CORS를 검색하면 가장 위에 나오는 MDN을 한 번 읽어본기만 해도 이해할 수 있는 내용이다. 만약 이 글이 이해가 안된다면, MDN에는 친절하게 그림과 함께 설명되어 있고, 친절하게 설명되어 있는 블로그들이 많다.

 

하지만 이 글을 적게 된 이유는 나처럼 이 글들을 읽고 이해가 안되는 부분이 있는 사람이 있을 것 같아서이다.

 

내가 이해가 안되는 부분은 보안상 문제라는 부분이었다.

처음에 나는 보안상 문제라고 하여,

허가 받지 않은 클라이언트가 서버의 정보를 몰래 빼오려고 요청하는 것을 막는 것인줄 알았다.

API를 만들어서 내 사이트에만 뿌리고 싶은데, 다른 사용자들이 맘대로 가져가서 사용하려고하는 것을 막으려는 건 줄 알았다.

 

하지만 이렇게 이해를 하면 막히는 부분이 생긴다. 

 

서버에 정보를 요청하면 정보는 보내주지만, 단지 http header에 { Access-Control-Allow-Origin : 허용할 주소 } 를 넣어서 보내고,

이 http header를 클라이언트의 브라우저에서 확인한 후, 자신이 허용할 주소가 아니라면 정보를 클라이언트에게 보여주지 않는 것이다.

 

서버에서 정보는 잘 보내줬는데 클라이언트에서 막을까?라는 생각과 내가 생각한 보안 문제가 아닐 것이라는 의심을 하였다.

그리고 그 이유를 찾아보았고, 맞는지는 모르겠지만 어느 유튜브에서 그 이유를 들을 수 있었다. 유튜브의 출처는 글 맨 하단에 작성하였다.

 

내가 알게된 CORS 정책의 이유를 예시를 들어서 설명하면,

 

내가 서비스를 만들었는데, a.com이라는 사이트를 만들고, b.com이라는 WEB API를 만들었다고 가정하자.

a.com에서는 로그인 한 후, 그 정보를 이용하여 b.com에서 데이터를 가져올 수 있다.

 

이런 상황에서 Trudy라는 정보를 탈취하고 싶은 사람은 t.com이라는 나쁜 사이트를 만들었다.

 

t.com에 사용자가 접속하면, b.com으로 정보를 요청해서 받아온다.

이 때, 클라이언트에 저장되어 있는 쿠키 같은 정보를 이용하여 사용자가 로그인되어 있는 상태로 요청하여 정보를 캐올 수 있다.

 

이 때 b.com에는 a.com만 허용하는 CORS 설정을 해놓았다면,

t.com에서 b.com으로 요청해서 받아오는 정보는 CORS 오류가 발생하게 되어 t.com한테 정보를 탈취당하지 않을 수 있다.

 

맥락과 흐름이 이렇게 이루어져, CORS는 이런 보안을 위하여 존재하는 정책이고,

이 부분도 시간이 난다면 그림과 함께 자세하게 설명하겠다.

 

 

[회고] CORS에 대한 공부를 하고,,, 

CORS에 대해 공부를 하며, 생각보다 보안의 의미가 크고, 글을 읽으며 내가 네트워크 보안이라는 과목을 듣지 않았다면 이해를 한 번에 할 수 없었을 것이라 생각이 들어, 전공에 대한 기초 지식의 중요성을 느꼈다...

 

그리고 문제를 해결할 때, 문제가 해결되었다고 끝내는 것이 아니라, 해결할 때 들었던 의문점들을 제대로 해소해야되겠고, 왜라는 의문을 더 깊게 해야되겠다는 생각이 들었다.

 

 

 

참고한 사이트

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

 

교차 출처 리소스 공유 (CORS)

교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라

developer.mozilla.org

developer.mozilla.org/ko/docs/Web/Security/Same-origin_policy

 

동일 출처 정책

동일 출처 정책(same-origin policy)은 어떤 출처에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한하는 중요한 보안 방식입니다. 동일 출처 정책은 잠재적으로

developer.mozilla.org

youtu.be/6QV_JpabO7g

velog.io/@yejinh/CORS-4tk536f0db

 

Same-Origin Policy 동일 출처 정책과 CORS 에러

동일 출처 정책 Same-Origin Policy 동일 출처 정책(same-origin policy)은 어떤 출처에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한하는 중요한 보안 방식입니다.

velog.io

coding-groot.tistory.com/91

 

CORS Error의 올바른 해결법

CORS Error에 대해서 알아보자! * 이 글은 Flask로 예시를 보여주지만 딱히 Flask를 몰라도 이해하는데 아무 상관이 없을 겁니다! Flask 자체가 간결하고 간단하기 때문에 모르는 사람도 어떤 코드인지 �

coding-groot.tistory.com

velog.io/@jmkim87/%EC%A7%80%EA%B8%8B%EC%A7%80%EA%B8%8B%ED%95%9C-CORS-%ED%8C%8C%ED%97%A4%EC%B3%90%EB%B3%B4%EC%9E%90

 

지긋지긋한 CORS 파헤쳐보자

CORS (Cross Domain) 서버와의 통신을 위해 ajax나 XMLHttpRequest를 사용하다보면 CORS 에러가 나오는 경우가 종종 발생합니다. 할때마다 설정 방법이나 우회 방법을 항상 찾다보니 매번 고생하는거 같아 ��

velog.io

 

반응형

+ Recent posts