SOP와 CORS

SOP와 CORS에 대해 알아봅니다

이 글을 읽으면

  • SOP와 CORS가 각각 왜 필요한지 알 수 있습니다
  • CORS를 해결하는 방법에 대해 알 수 있습니다

SOP

Same Origin Policy의 약어. 즉, Origin이 같은 경우에만 요청을 보낼 수 있다는 의미입니다.

어떤 요청인가요?

API요청을 의미합니다. 이미지나 js,css 같은 자원들은 origin이 달라도 요청을 할 수 있습니다.

오리진이란?

naver에가서 document.location.origin을 치면 https://www.naver.com 이 나옵니다.

즉, 현재 보고있는 페이지가 어디로 부터 온것인지출처에 대한 정보(출처 = origin)를 나타냅니다.

그렇군요, 그러면 Same Origin Policy는 무엇인가요?

현제 페이지의 origin과 같은 서버에게만 요청을 보낼 수 있다는 브라우저의 정책입니다. 서버는 누구로부터 요청을 받았는지 특별한 작업을 해놓지 않는 이상 신경쓰지 않습니다.

이미지나 js파일은 도메인이 달라도 잘 가져오던데요?

맞습니다, css, js, image, iframe, embeded, video등은 origin이 달라도 잘 가져옵니다.

그러면 SOP가 무슨 의미가 있나요? 작동을 안하는거 아닌가요?

  • API 요청
  • outter page에서 inner iframe의 DOM에 접근

위의 두가지 경우에는 origin이 같아야지만 일을 할 수 있습니다.

origin이 완전이 같아야 하나요? 보통 www.api.my-site.com 이런식으로 subdomain 붙이곤 하잖아요

완전히 같을 필요는 없지만, www.my-site.comwww.api.my-site.com은 origin이 다르다고 인식합니다.

다만, port번호(같다면)나 path variable은 origin에 영향을 주지 않습니다.

SOP는 왜 필요한건가요?

1995년 Netscape에서 iframe기능을 출시했습니다. 그런데 이 기능은 사용자에게 보안 이슈를 일으킬 여지가 있었습니다. 예를 들어보겠습니다.
(1) 병민은 gmail에 로그인 합니다
(2) 해커는 비트코인을 꽁짜로 준다는 가짜 사이트를 만듭니다
(3) 해커가 병민에게 메일을 보냅니다
(4) 욕심많은 병민은 ‘와우!!!’라며 메일을 열고 버튼을 클릭합니다
(5) 해커가 만든 사이트는 iframe으로 gmail inbox를 불러옵니다. SOP가 없으면 로그인 정보가 cookie에 있으니까 마치 병민이 요청한것처럼 데이터를 요청합니다. 그리고 또 SOP가 없으면 origin이 달라도 iframe의 document에 접근해서 javascript로 데이터를 긁어올 수 있습니다. 해커는 이렇게 긁어온 메일들을 자신의 서버로 전송합니다.
(6) 병민은 이렇게 개인정보가 유출되었습니다.

그래서 origin이 같은 경우에만 iframe에서 DOM에 접근하도록 허용했습니다.

iframe은 잘 안쓰니까 괜찮은데, 날씨 API나 포켓몬 API를 사용하고 싶을때는 어떻게 하나요?

[css, js, image, iframe, embeded, video..] 등은 origin이 달라도 잘 가져온다고 언급 했었는데, api요청도 예외를 만들 수 있습니다.

CORS

Cross Origin Resource Sharing.

SOP의 예외 사항입니다. 서버로부터 받은 응답 문서(HTTP문서)의 Header부분에 있는 Access-Control-Allow-Origin필드에 요청을 보낸 브라우저의 domain이 들어 있으면 리소스 공유가 가능하다. 즉, origin이 달라도 서버가 해당 origin과의 소통을 허용하면 통신이 가능 합니다.

Access-Control-Allow-Origin ?

200 OK
Access-Control-Allow-Origin: http://my-site.com
Connection: Keep-Alive
Keep-Alive: timeout=5, max=997
Last-Modified: Mon, 18 Jul 2016 02:36:04 GMT
Server: Apache
Set-Cookie: mykey=myvalue; expires=Mon, 17-Jul-2017 16:06:00 GMT; Max-Age=31449600; Path=/; secure
...

맨 위에 있는 `Access-Control-Allow-Origin`에 http://my-site.com이라고 적어주면, 현제 페이지(http://my-site.com)에서 서버(http://api.my-site.com)로 요청을 보낼 수 있습니다.

그런데, 저 Access-Control-Allow-Origin은 브라우저가 요청을 보내고 난 후에 응답값으로 오는거잖아요. 그러면 서버에서 이미 처리가 다 끝난거 아닌가요?

맞습니다. 사실 브라우저가 요청을 보내고 -> 서버에서 처리한뒤 응답값을 보냈는데 -> Access-Control-Allow-Origin에 현재 사이트 주소가 적혀있지 않으면 말이 안됩니다. 이미 서버에서 처리는 끝났을테니까요. 그래서 브라우저는 실제 api요청을 보내기 전에 preflight 요청을 먼저 보냅니다.

preflight…?

pre – flight

비행하기 전에 기체를 점검하는것을 의미합니다.

브라우저도 실제 API를 보내기 전에 현재 page의 origin이 서버에서 허용하는 origin인지 점검합니다.

OPTIONS /resource/foo
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: origin, x-requested-with
Origin: https://foo.bar.org

이런 요청을 보내면 서버가 아래와 같이 응답을 돌려줍니다

HTTP/1.1 204 No Content
Connection: keep-alive
Access-Control-Allow-Origin: https://foo.bar.org
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE
Access-Control-Max-Age: 86400

이제 브라우저가 저 Access-Control-Allow-Origin를 보고 진짜 요청을 보낼지 말지 결정합니다.

엇, 그러면 요청을 보낼때마다 브라우저는 preflight를 보내는 건가요? 비효율적이지 않나요?

맞습니다. 그래서 브라우저는 preflight 요청에 대한 응답을 caching해놓습니다. 그래서 처음에만 preflight요청이 보내지고 그 이후부터는 한번만 요청을 보냅니다.

그러면 prefight에 실패한 경우에도 캐싱을 하나요?

음,,이건 아직 테스트를 못해봤습니다만, 실패한 경우에도 캐싱을 할것 같습니다. 여기서 실패했다는것은 서버로 부터 응답받은 response header에 Access-Control-Allow-Origin과 현재 api요청을 보낸 페이지의 origin이 다르다는것을 의미합니다.

얼마나 캐싱할지 어떻게 정하나요?

Access-Control-Max-Age로 조절합니다.

그러면 모든 요청이 86400초 동안 preflight없이 가나요?

이것도 테스트를 못해봤는데, 아마 origin이 같은 api 요청에만 캐싱이 적용될것 같습니다.

혹시 CORS없이도 그냥 요청을 보낼 수는 전혀 없는건가요?

이미지 같은 자원에 대한 요청이 아니고, CORS도 아닌 다른 예외 조항이 있습니다. 바로 Simple Request!.

아주 심플한 요청은 CORS 검사 없이도 그냥 보낼 수 있습니다. 다만 조건은 simple하지 않습니다.

mdn : https://developer.mozilla.org/ko/docs/Web/HTTP/CORS#%EB%8B%A8%EC%88%9C_%EC%9A%94%EC%B2%ADsimple_requests

외우기 보다는, 그냥 이런게 있구나! 정도만 알면 될듯 싶습니다.

이상입니다. 읽어주셔서 감사합니다.

참고

  • https://evan-moon.github.io/2020/05/21/about-cors/
  • https://developer.mozilla.org/ko/docs/Glossary/Preflight_request
  • https://developer.mozilla.org/ko/docs/Web/HTTP/CORS
  • https://jakearchibald.com/2021/cors/

Leave a Reply

Your email address will not be published.