CORS와 SOP

StarSeeker·2022년 1월 24일
0
post-thumbnail
post-custom-banner

React 와 node.js로 토이 프로젝트를 하다보니 cors 이슈가 발생해 이참에 어렴풋이 알던 개념을 다시 정리 해보고자 포스팅을 열었다.

SOP

SOP는 동일출처원칙으로 하나의 웹페이지에서 다른 출처로 리소스를 요청할 수 없는 것을 말한다.
여기서 동일 출처라는 것은

  • 두 URL의 프로토콜
  • 포트 (en-US)(명시한 경우)
  • 호스트 (en-US)가 모두 같아야 동일한 출처로 인식 된다.

동일 출처 원칙을 지키지않으면 어떤 보안문제가 발생할까?

만약 은행 웹사이트에 사용자가 로그인 했다고 가정했을시, 그 세션을 유지 하고 있는 상태라고 가정하자. 그때 이메일이나 모종의 유인으로 해커의 웹페이지에 우연히 접근했다면, 서버에게 그대로 은행계정의 정보를 요청할 수 있다. 이미 로그인된 상태이기 때문에!

따라서 서버측에서는 이 리소스를 요청한 곳이 믿고 신뢰할수 있는 곳인지 확인하는 것이 필요하고, 브라우저 측에서도 이러한 부분을 SOP 정책으로 막고 있는 것이다.

그런데 과거와 달리 웹페이지가 복잡해지면서 동일 출처가 아닌 다른 곳에 요청해야할일이 많아 졌고 이를 해결할 필요가 있었다.
그래서 SOP를 해결하는 방법으로 Form 태그Script 태그를 이용하는 간접적인 방법으로 다른 에 요청을 하였다.

그리고 그러던 와중에 자바스크립트에서도 네트워크 관련 메서드가 추가되어 이것을 서버측에서 확인하는 방식으로 동일 출처 원칙을 해결했는데 이것이 CORS 라고 한다.

CORS

CORS 요청에는 안전한 요청그 밖의 안전하지 않은 요청이 있다.
안전한 요청은 다음과 같다.

  • 안전한 메서드(safe method) – GET이나 POST, HEAD를 사용한 요청
  • 안전한 헤더(safe header) – 다음 목록에 속하는 헤더
    Accept
    Accept-Language
    Content-Language
    값이 application/x-www-form-urlencoded이나 multipart/form-data, text/plain인 Content-Type

이 이외엔 안전하지 않은 요청으로 판단 되며 두 요청의 차이점은
위에 언급된 form/script 태그로 요청을 만들수 없는 PUT, DELETE, PATCH 등과 같은 메서드를 말하며, 안전하지 않은 요청의 경우 'preflight'라는 서버에 크로스오리진 요청을 확인하는 사전 요청을 보내서 이 요청이 유효한지 확인하는 과정을 거칩니다.

안전한 요청

GET /request
Host: anywhere.com
Origin: https://javascript.info
...

만약 위의 요청을 보냈을 때,

일단 서버는 origin 헤더에 있는 값을 확인하고 허용된 origin 이라면 Access-Control-Allow-Origin 헤더에 허가된 오리진 정보나 '*'가 담겨서 응답을 하게 됩니다.
만약 허락되지 않은 오리진이라면 결과값에 자바스크립트로 접근할수 었고 cors 오류를 콘솔에 띄웁 니다.

안전하지 않은 요청

안전하지 않은 요청의 경우 브라우저에서 본요청을 보내기 전에 preflight요청을 보내게 됩니다. preflight 요청은 OPTION 메서드로 요청을 보내게 되고 아래의 두 헤더, 빈 내용으로 요청을 보내게 됩니다.

  • Access-Control-Request-Method 헤더 – 안전하지 않은 요청에서 사용하는 메서드 정보가 담겨있습니다.
  • Access-Control-Request-Headers 헤더 – 안전하지 않은 요청에서 사용하는 헤더 목록이 담겨있습니다. 각 헤더는 쉼표로 구분됩니다.

서버는 허용된 요청이라면 아래와 같은 내용의 헤더와 빈 본문이 담긴 응답을 보내줍니다.

  • Access-Control-Allow-Origin – *이나 요청을 보낸 오리진 이어야 합니다(예: https://javascript.info)
  • Access-Control-Allow-Methods – 허용된 메서드 정보가 담겨있습니다.
  • Access-Control-Allow-Headers – 허용된 헤더 목록이 담겨있습니다.
  • Access-Control-Max-Age – 퍼미션 체크 여부를 몇 초간 캐싱해 놓을지를 명시합니다. 이렇게 퍼미션 정보를 캐싱해 놓으면 브라우저는 일정 기간 동안 preflight 요청을 생략하고 안전하지 않은 요청을 보낼 수 있습니다.

자격증명

CORS 요청의 경우 기본적으로 쿠키나 HTTP 인증 같은 자격 증명(credential)이 함께 전송되지 않습니다. 왜냐하면 자격증명이 된 요청은 서버에 접근 권한이 높은 요청을 마음대로 할수 있기때문에 더 강한 보안정책이 필요합니다.
따라서 cors에서는 credentials: "include" 옵션으로 이 요청에 자격증명과 관련된 데이터가 같이 포함되도록 명시를 해주어야합니다.
그 다음에 자격 증명 정보가 담긴 요청을 서버에서 받아들이기로 동의했다면 서버는 응답에 Access-Control-Allow-Origin 헤더와 함께 Access-Control-Allow-Credentials: true 헤더를 추가해서 보냅니다.

200 OK
Access-Control-Allow-Origin: https://javascript.info
Access-Control-Allow-Credentials: true

중요!!

자격 증명이 함께 전송되는 요청을 보낼 땐 Access-Control-Allow-Origin에 *을 쓸 수 없습니다. 위 예시에서처럼 Access-Control-Allow-Origin엔 정확한 오리진 정보만 명시되어야 합니다.
이런 제약이 있어야 어떤 오리진에서 요청이 왔는지에 대한 정보를 서버가 신뢰할 수 있기 때문입니다.

profile
춤추듯 개발하고 싶은 사람
post-custom-banner

0개의 댓글