[스터디] SOP, CORS & Preflight

2023. 3. 11. 22:42FrontEnd/보안

작성자알 수 없는 사용자

728x90
반응형

 

안녕하세요. 기깔나는 사람들에서 FrontEnd를 맡고 있는 제시ca입니다.

이번에 다룰 내용은 프론트 개발을 하다 보면 종종 겪어봤을 에러 범인 CORS 입니다.

도대체 CORS는 무엇이고, 어떻게 동작 되는 것인지 알아보려고 합니다.

 

브라우저에서 보안을 위한 정책이 크게 SOP, CORS 두 가지가 있습니다.


💡 Origin=출처?

출처는 scheme(protocol) + hostName + port를 합친 것을 말합니다.예) http://example.com:3000

출처가 동일하다는 것은 scheme(protocol) + hostName + port 이 동일하다는 것입니다.


SOP (Same Origin Policy 동일 출처 정책)

Javascript는 브라우저에서 제공하는 DOM 객체를 조작할 수 있으며 브라우저 내장 XMLHttpRequest 개체를 통해 서버와 상호 작용할 수 있습니다. 이에 SOP는 Javascript가 상호작용 할 수 있는 웹 콘텐츠에 대한 제한을 둘 수 있도록 합니다. 내 서버가 아닌 다른 서버에서 받아온 데이터를 기본적으로 차단합니다.

 

[예제]

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script>
      function readIframeCookie(iframeId) {
        const iframe = document.getElementById(iframeId);
        const iframeDoc = iframe.contentWindow.document;
        const cookie = iframeDoc.cookie;
        alert(cookie);
      }
    </script>
  </head>
  <body>
    <button type="button" onclick="readIframeCookie('iframe')">
      ReadCookie
    </button>
    <iframe id="iframe" src="http://localhost:3000"></iframe>
  </body>
</html>

localhost:3000 으로 테스트 서버를 하나 띄워놓은 상태에서 위의 소스를 이용했고, 요청한 소스의 서버 포트는 5500으로 다른 출처입니다.

ReadCookie 버튼을 누르게 되면 아래와 같은 에러 문구를 볼 수 있습니다.

교차 출처 프레임 내부의 문서 개체에 접근할 수 없다고 브라우저가 알려주는 것을 알 수 있습니다.


CORS (Cross-Origin Resource Sharing 교차 출처 리소스 공유) 

SOP가 기본적으로 사용되지만, 불가피 하게 서로 다른 서버에서 통신을 해야 될 경우가 있는데 SOP를 완화하여 사용하기 위한 기술이 CORS입니다.
즉, 출처(Origin)가 달라도 서버에서 CORS를 허용한다면, 다른 출처(Origin)로 응답을 보낼 수 있습니다. 
이 기술은 브라우저가 리소스 로드를 허용해야하는 자체 출처 이외의 모든 출처(도메인, 포트 등)를 서버가 표시할 수 있도록 하며, 서버가 실제 요청을 허용하는지 확인하기 위해 브라우저가 원본 간 리소스를 호스팅하는 서버에 실행 전 요청을 하는 매커니즘(Preflight)에 의존합니다.

CORS를 활성화 하려면 서버가 브라우저에 CORS request를 처리한다고 알려야 합니다. (Access-Control-Allow-Origin 설정)
브라우저는 서버에 CORS 요청을 보내면 응답 헤더에 Access-Control-Allow-Origin 헤더를 보고 응답의 허용 여부를 결정합니다.
(Access-Control-Allow-Origin:* 는 credentials 옵션이 없는 요청에 한해 모든 Origin이 해당 리소스에 접근 가능하도록 허용합니다. 보안에 취약함)


CORS는 Credentialed Request, Simple Request와 Preflight Request 세 가지 요청 방식이 있습니다.

 

Simple Request - 단순 요청

Preflight 요청을 생략하고 서버에 본 요청을 하는 방식이며, 응답 헤더에 Access-Control-Allow-Origin를 보내면 브라우저가 CORS 정책 위반 여부를 검사합니다.

이는 아래 조건을 만족할 때만 가능합니다.

1. 요청 메서드는 GET,HEAD,POST 중 하나

2. Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, Width 헤더일 경우

3. Content-Type 헤더가 application/x-www-form-urlencoded, multipart/form-data, text/plain 중 하나

 

Credentialed Request - 인증된 요청

클라이언트에서 서버에게 자격 인증 정보를 같이 동봉해서 요청할때 사용되는 요청입니다.

여기서 말하는 자격인증 정보란 세션 ID가 저장되어있는 쿠키 혹은 Authorization 헤더에 설정하는 토큰 값 등을 말합니다.

서버에 인증된 요청을 보내는 방법으로는 fetch 메서드를 사용하거나, 라이브러리를 이용하는 방법등 다양하며, 아래 흔히 쓰는 axios 예시로 담았습니다.

axios.post('https://example.com:1234/users/login', { 
    profile: { username: username, password: password } 
}, { 
	withCredentials: true
})

만일 Credentials 옵션은 true를 줬는 데, Access-Control-Allow-Origin:* 를 설정한다면 에러가 발생합니다. 이럴 때는 Access-Control-Allow-Origin 에 구체적인 도메인을 설정 해야 합니다.

특히, 주의 해야 할 점은 응답 헤더에 Access-Control-Allow-Credentials: true가 명시되지 않으면 응답은 브라우저에 의해 무시됩니다.

즉, 요청하는 클라이언트에서도 credentials 옵션을 설정 해야 하며, 서버에서 또한 헤더 설정을 해주어야 합니다.

 

Preflight Request - 예비 요청

단순 요청이나 인증된 요청이 아니라면 실제 통신하기 전에 미리 통신을 해서 정책이 위반되었는지 확인하는 것입니다. OPTIONS 메서드가 사용되며, HTTP요청을 다른 도메인의 리소스로 요청하여 실제 요청을 전송해도 안전한지 확인합니다.

허용되지 않는 요청의 경우 405(Method Not Allowed) 발생시키고 실제 요청은 전송하지 않습니다.

응답 헤더에는 Access-Control-Request-* 가 포함되어있는 것을 확인 할 수 있는데, preflight에서 사용되는 헤더입니다.


Preflight 그리고 보안 취약점

Preflight 에서 사용되는 OPTIONS 메서드는 서버에 대해 허용된 통신 옵션을 요청합니다.

웹 메서드 공격을 위해서 해당 메서드를 이용해 서버의 메서드 허용 대상을 확인할 수 있으므로 보안에 취약할 수 있습니다.

때문에, 프로젝트에서 웹 보안 취약점 점검을 시행할 경우, 서버에서 OPTIONS 메서드 사용을 막는 경우가 있을 수 있으며, 이럴 경우 서버의 API 사용이 불가하게 되므로 팀 간의 적절한 협의가 필요합니다.

 


 


참고자료

🔗 - https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy

🔗 - https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

🔗 - https://medium.com/@zhaojunemail/sop-cors-csrf-and-xss-simply-explained-with-examples-af6119156726

🔗 - https://brownbears.tistory.com/336

 

 

 

 

 

728x90
반응형