CORS(교차 출처 리소스 공유), Same-origin policy(동일 출처 정책)

Minjae Kwon·2021년 3월 1일
2

 🍉   Learning Journal

목록 보기
31/36
post-thumbnail

CORS 는 Cross-Origin Resource Sharing 의 준말로, 교차 출처 리소스 공유 라고 해석된다. 브라우저와 서버가 서로 통신할 때 등장하는 개념으로서, 'HTTP 헤더'를 기반으로 동작한다. 서버는 어떤 출처가 자신의 리소스를 가져갈 수 있는지 설정하고, HTTP 헤더를 통해 요청의 출처를 확인한다.

헤더와 더불어 '프리플라이트 preflight' 메커니즘도 사용한다. 브라우저가 실제 요청에 앞서 자신이 어떤 HTTP 메소드를 사용할 지 서버에 귀띔을 보내고, 실제 요청이 허락될지 확인하는 과정이다. 모든 HTTP 요청이 프리플라이트를 띄우지는 않는다. 예를 들어, 서버에서 정보를 읽어오기만 하는, 상대적으로 안전한 get 요청은 프리플라이트를 띄우지 않는다. 반면, 서버에 정보를 업데이트하는, 즉 정보 변환의 위험이 있는 post 요청의 경우에는 프리플라이트에 해당하는 http 메소드인 options 가 먼저 서버에 날라가, 허용될 지 여부를 알아온다. 이들을 포함하여 CORS 요청 종류는 다음 4가지로 나뉜다.

  • Simple Request
  • Preflight Request
  • Credential Request
  • Request without Credential

💡 Simple Request 단순 요청, Preflight Request 프리플라이트 요청

방금 get 요청은 preflight 를 띄우지 않는다고 했는데, 이런 것이 단순 요청에 해당한다. MDN 에 따르면, 아래의 조건 사항을 모두 만족하는 경우 이 단순 요청에 해당한다고 본다. 이외에는 프리플라이트를 띄운다.

📌 HTTP 메소드는 다음 셋 중 하나일 것

  • GET
  • HEAD
  • POST

📌 브라우저 기본 세팅으로 설정된 헤더 - 예컨대 Connection, User-Agent 등 - 외에 커스텀 헤더 내용은 아래 항목만 가능

  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type (단, 아래 조건을 만족해야 함)

📌 Content-Type 헤더의 값은 다음 셋 중 하나일 것

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

📌 요청에서 이벤트 리스너가 사용되지 않아야 함
📌 요청에서 ReadableStream 이 사용되지 않아야 함

💡 Credential Request, Request without Credential

서버와 쿠키, 세션 등을 통해 통신한다면 반드시 withCredentials 값을 true 로 설정해주어야 한다. (이 때 서버는 반드시, Access-Control-Allow-Origin 값으로서 와일드 카드 * 를 사용하지 않고, 정확한 출처를 명시해주어야 한다. ) 이를 Credential Request 로 분류한다. withCredentials 값을 별도로 설정하지 않는 경우, 기본값은 non-credential 요청이다.

💡 동일 출처 정책 same-origin policy

출처(origin)는 프로토콜, 포트(명시된 경우), 호스트 로 구성된다.

동일 출처는 두 URI 의 프로토콜, 포트, 호스트가 모두 같음을 의미한다. (프로토콜은 URI scheme 으로 불리우기도 한다. 👉🏻 관련링크)

동일 출처 정책은 웹 브라우저 보안을 위하여 출처가 동일한 서버로만 통신을 주고 받도록 하는 보안 정책으로서, 대부분의 브라우저가 따르고 있다. 어떤 이유들 때문일까?

  • 스크립트 삽입을 통한 잠재적 XSS 공격 위험 차단
  • 데이터 기밀 유지를 위해, 관계없는 사이트에서 제공된 콘텐츠는 클라이언트 단에서 차단
  • 현대 웹 어플리케이션은 authenticated 된 사용자의 세션을 유지하기 위해 http cookie 에 의존
  • 웹 어플리케이션이 authorised 된 사용자의 세션 정보를 http cookie 에 담아 광범위하게 사용하는 경우, 출처가 다른 페이지에서 스크립트를 이용해 해당 쿠키정보를 추출할 수 있기 때문

🌿 동일 출처 예시

아래는 기준이 되는 URI 이다.


프로토콜 http:// 의 포트는 80이 기본값이다. 즉 위 URI 는 http://diy.market.com:80/dir/page.html 과 같다. 이 URI 와 비교하여 동일 출처 URI 들을 구분해보면 다음과 같다.

❗️ Internet Explorer 두 가지 예외사항

동일 출처 정책은 브라우저에서 동작하는 제약이기 때문에, 브라우저마다 상이하게 적용될 수 있으며 대표적으로 Internet Explorer 는 아래 예외사항을 둔다.

1) 신뢰할 수 있는 사이트: 양쪽 도메인 모두 '높음' 단계의 보안 수준인 경우 동일 출처 제약을 적용하지 않는다.
2) 포트: 포트 검사를 하지 않는다. 즉 Internet Explorer 에서 위의 네 번재 예시는 동일 출처로 간주된다.

이와 같은 두 예외는 모두 비표준이며, 다른 브라우저는 따르지 않는다.


🌿 동일 출처 정책 범위

동일 출처 정책은 스크립트에만 적용된다. 이미지, CSS 나 동적으로 로딩된 스크립트들은 그에 대응하는 HTML 태그, 이를테면 img, video, embed, iframe 등을 사용함으로써 교차 출처가 허용된다.

CSRF 공격은 이런 점을 악용한 공격이다. 동일 출처 정책은 cross-site 읽기만 방어할 뿐, 쓰기를 예방하지 못한다. 동적으로 로딩된 스크립트가 어떤 요청을 보내는 것을 막을 수는 없다. 만약 cross-site 가 사용자의 인증 정보가 담긴 쿠키를 채가서 서버에 있는 정보를 탈취하려고 한다면, 서버에서는 SameSite 쿠키 설정을 통해 이를 예방할 수 있다.

동일 출처 정책은 중요한 보안 정책이지만, 타이트한 기준을 가지고 있기 때문에 로컬 작업을 하다보면 종종 아래와 같은 에러를 마주치기도 한다.

🚨 XMLHttpRequest cannot load 'http://localhost:3000'. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4000' is therefore not allowed access.

이를 완화하기 위해서, 출처가 다른 도메인에서의 AJAX 요청이라도 서버단에서 데이터 접근 권한을 허용할 수 있도록 CORS 가 등장하게 되었다.

👩🏻‍🎓 코드스테이츠에서 학습 당시, 기본 Web API 인 fetch API 를 사용했을 때는 CORS 에러가 나고, third-party 라이브러리인 axios 를 설치해서 사용하면 별도의 에러가 나지 않았던 경험이 있다. fetch API 는 동일 출처 정책을 따르기 때문에, 로컬에서 작업할 때 위와 같은 에러를 유발할 수 있다. 임시 방편으로 서버단에서 Access-Control-Allow-Origin: * 로 설정하여 해결할 수 있지만, 이후에는 반드시 정확한 출처로 변경해주어야 한다.


[ 참고자료 ]

profile
Front-end Developer. 자바스크립트 파헤치기에 주력하고 있습니다 🌴

0개의 댓글