SOP(Same Origin Policy)는 웹 브라우저가 출처(origin)를 기준으로 웹 서비스의 자원을 분리시켜 출처가 다른 웹 서비스가 웹 서비스의 자원을 무단으로 조회, 조작 하는 것을 방지하는 정책이다. 즉, 브라우저 내에서 웹 서비스를 분리시키는 정책이다.
origin은 웹 서비스의 출처이다. same origin은 브라우저가 열고 있는 웹 서비스와 출처가 같다고 인정하는 웹 서비스를 말한다. same origin인 웹 서비스는 현재 브라우저가 열고 있는 웹 서비스와 자원을 공유할 것이다.
반대로 cross origin은 브라우저가 열고 있는 웹 서비스와 출처가 다르다고 인정하는 웹 서비스를 말한다. cross origin인 웹 서비스는 현재 브라우저가 열고 있는 웹 서비스와 자원을 공유하지 못할 것이다.
그렇다면 same origin과 cross origin의 기준 즉, 출처가 같다는 것의 기준은 무엇일까?
URL 구조에서 scheme, host, port가 같으면 same origin이라고 여긴다. 이들 중 하나라도 다르다면 cross origin이라고 여긴다.
same origin과 cross origin의 기준은 브라우저에 상관 없이 모든 브라우저가 같다.
앞서 SOP가 브라우저에서 웹 서비스의 자원을 출처 단위로 분리시키는 정책이라고 하였다. SOP가 분리시킨다는 웹 서비스의 자원이 정확히 무엇일까? SOP는 브라우저에 어떻게 적용되는 것일까?
먼저, 웹 서비스의 쿠키는 origin별로 브라우저 내에서 구분되어 있다. 쿠키는 사용자 인증에 사용되는 보안에 매우 중요한 요소이다. 그렇기 때문에 쿠키는 브라우저 내부에서 origin별로 구분되어 있다.
다음으로, 웹 서비스는 cross origin으로부터 온 응답을 조회하지 못한다. 서버에 요청을 보내고 서버에서 이 요청에 대한 제대로 된 응답을 보내고 브라우저에서 응답을 수신하기는 할 것이다. 하지만 이 응답을 조회하는 것이 막히는 것이다.
그렇다면 브라우저에 왜 SOP를 적용하는 것일까? 브라우저에서 웹 서비스의 자원을 출처 단위로 분리시키는 것은 어떻게 보안에 도움이 되는 것일까?
origin별로 쿠키를 분리하는 이유는 따로 설명하지 않아도 그 이유를 쉽게 유추해볼 수 있다. 쿠키에는 사용자 인증에 필요한 세션 정보가 들어있다. 쿠키를 origin별로 구별하지 않으면 악의적인 사이트에서 다른 웹 사이트의 쿠키 정보를 빼돌려 사용자 인증에 사용할 수 있다.
처음 SOP에 대해 공부할 때 cross origin으로부터 온 응답을 조회하는 것이 금지되어있는 이유가 요청을 보낸 웹 페이지의 정보를 보호하기 위해서인줄 알았다. 하지만 이는 모순을 가지고 있었는데 뒤에서 설명할 CORS가 있기 때문이다. 만약 SOP의 의도가 현재 브라우저로 열고 있는 웹 사이트에서 악의적인 사이트로부터 응답을 받아 악의적인 코드가 실행되는 것을 막는 것이라면 말이 안되는게 CORS를 통해 요청에 대한 응답을 조회해도 될지 안될지 결정하는 결정권은 서버에게 있기 때문이다. 악의적인 사이트 입장에서는 당연히 CORS를 설정해서 자신이 보내는 악의적인 코드가 브라우저에 잘 전송되고 실행되어서 브라우저의 정보를 빼가기를 원할 것이다.
SOP에서 cross origin으로부터 온 응답을 조회하지 못하게 하는 것의 핵심은 현재 열고 있는 웹 사이트의 인증 정보를 보호하는 것이 아니라 현재 브라우저가 열고 있는 웹 페이지가 악의적인 웹 페이지일 수 있다는 가정 하에 악의적인 웹 페이지에서 다른 웹 페이지의 인증 정보를 담고 있는 응답을 받지 못하도록 막는 역할인 것이다.
예를 들어, example.com에 로그인한 상태에서 악의적인 사이트 attacker.com에 접속했고 attacker.com에서 JS 코드를 실행하여 example.com에 요청을 보낸다고 하자. 그럼 attacker.com에서 보낸 요청에는 example.com의 쿠키 정보가 함께 들어 있어 로그인한 상태로 요청을 보내게 된다. 왜냐하면 attacker.com에서 요청을 보낸 브라우저가 example.com에 로그인한 브라우저와 같은 브라우저이기 때문이다. attacker.com에서 example.com에 보낸 요청이 사용자 인증이 된 요청이기 때문에 만약 SOP가 적용되어있지 않았다면 개인정보가 담긴 응답을 attacker.com이 조회할 수 있을 것이다. 반면에 SOP가 적용되었다면 attacker.com이 요청을 보낼 수는 있어도 개인정보가 담긴 응답을 조회할 수 없을 것이다.
그런데 잘 생각해보면 attacker.com이 example.com에 사용자 인증이 된 상태로 요청을 보낸다는 것도 심각한 보안 취약점이다. 사용자 인증이 된 상태로 비밀번호 변경 요청이라도 보내게 되면 계정의 비밀번호가 공격자가 원하는 비밀번호로 바뀔 수도 있다. 모든 보안 메커니즘이 그렇듯 SOP도 모든 보안 취약점을 다루는 완전한 보안 메커니즘은 아니다. 여러 보안 메커니즘이 서로를 보안하며 더 안전한 인터넷 환경을 만드는 것이다. cross origin에서 요청을 보내는 취약점은 SOP가 아니라 CSRF에서 다룬다.
SOP는 scheme, host, port가 다른 origin으로부터 온 응답을 조회하지 못하는 정책이다. 하지만 scheme, host, port가 달라도 다른 origin에서 응답을 조회할 수 있는 예외 상황이 존재한다.
각각 이미지, CSS, JS를 불러오는 <img>, <style>, <script> 태그를 통해 불러오는 응답은 cross origin이라고 해도 예외적으로 조회할 수 있다. 그리고 이런 예외 사항이 XSS 공격의 취약점으로 발현되기도 한다.
나는 SOP에 대해 알아볼 때 "cross origin에서 요청을 보낸다"는게 무엇인지 잘 이해가 되지 않았다. 기존 상식으로는 웹 요청을 보낸다는 것은 클라이언트인 내가 직접 chrome이나 firefox같은 웹 브라우저를 이용해서 웹 서버에 요청을 보내는 것이였다. 그래서 웹 페이지에서 요청을 보내는게 어떤 의미인지 잘 이해할 수 없었다.
웹 서버로 요청을 보내는 주체가 꼭 사람이 아닐 수도 있다. 어떤 프로그램이 요청을 보낼 수도 있고, 웹 서버가 보낼 수도 있고, 웹 페이지에서 보낼 수도 있다. 브라우저에서 열고 있는 웹 서비스는 JS을 이용해서 웹 서버로 요청을 보낼 수 있다. JS의 fetch, XML을 사용하면 브라우저에서 열고 있는 웹 서비스에서 웹 요청을 만들고 보낼 수 있다.
https://velog.io/@ymail837/%EC%9D%BC%EB%B0%98-Fetch-XHR
(미완성)
웹 서비스를 만들다 보면 origin이 다른 웹 서비스와 데이터를 주고받아야 하는 경우가 있을 수 있다. 예를 들면, naver.com이 mail.naver.com, blog.naver.com와 데이터를 주고받아야 한다고 하자. 이 웹 서비스들은 서로 origin이 다르기 때문에 SOP에 의해 서로 데이터를 주고받을 수 없을 것이다. 하지만 CORS를 이용하면 origin이 다르더라도 서로 데이터를 주고받을 수 있다. 이와 같이 웹 서비스 개발자의 의도하에 origin이 다르더라도 서로 데이터를 주고받을 수 있도록 하는 방법이 CORS이다.
cross origin에서 서버가 보낸 응답을 조회할 수 있도록 허락하는 주체는 서버이다. 즉 서버에서 CORS를 설정해야 한다.