항해 99 5주차 WIL

정현욱·2022년 6월 12일
0

CORS란 무엇인가?

Cross-Origin Resource Sharing(교차 출처 리소스 공유)의 약자로

브라우저에서 실행 중인 스크립트에서 시작되는 cross-origin HTTP 요청을 제한하는 브라우저 보안 기능입니다.

에러 발생 예시

기본적으로 CORS 관련 에러가 발생하면 서버에 Request 할 때 정상적인 데이터를 받아오지 못합니다.

이 때 브라우저 개발자 도구로 확인해보면 아래와 같은 에러 메시지가 나타납니다.

🚨 Access to fetch at ‘http://localhost:8080/’ from origin ‘http://localhost:8000’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.

이런 CORS 관련 이슈는 모두 CORS 정책을 위반했기 때문에 발생하는 것입니다

CORS는 어떻게 동작하는가?

기본적으로 웹 클라이언트 어플리케이션이 다른 출처의 리소스를 요청할 때는 HTTP 프로토콜을 사용하여 보내게 됩니다. 이 때 브라우저는 요청 헤더에 Origin이라는 필드에 요청을 보내는 출처를 함 께 담아 보냅니다.

그럼 Origin은 무엇일까요?
서버의 위치를 의미하는 https://google.com과 같은 URL들은 마치 하나의 문자열 같아 보여도,

사실은 여러 개의 구성 요소로 이루어져있습니다.

이때 출처는 Protocol과 Host, 그리고 :80, :443과 같은 포트 번호까지

모두 합친 것을 의미합니다.

즉, Origin은 서버의 위치를 찾아가기 위해 필요한 가장 기본적인 것들을 합쳐놓은 것입니다.

또한 출처 내의 포트 번호는 생략이 가능한데,

이는 각 웹에서 사용하는 HTTP, HTTPS 프로토콜의 기본 포트 번호가 정해져있기 때문입니다.

HTTP가 정의된 RFC 2616 문서를 보면 다음과 같이 기본 포트 번호가 함께 정의되어있는 것을 볼 수 있습니다.

다시 CORS가 어떻게 동작하는지에 대해 돌아와서

서버가 요청에 대한 응답을 할 때 응답 헤더에 Access-Control-Allow-Origin이라는 값에

“이 리소스를 접근하는 것이 허용된 출처”를 내려주고,

이후 응답을 받은 브라우저는 자신이 보냈던 요청의 Origin과 서버가 보내준 응답의

Access-Control-Allow-Origin을 비교해본 후 이 응답이 유효한 응답인지 아닌지를 결정합니다.

HTTP Preflight란 무엇인가?

이름에서 짐작할 수 있듯, Preflight Request는 예비 요청과 본 요청으로 나뉘어 전송됩니다.

먼저 서버에 예비 요청(Preflight Request)를 보내고 서버는 예비 요청에 대해 응답하고,
그 다음에 본 요청(Actual Request)을 서버에 보내고, 서버도 본 요청에 응답합니다.

Preflight Request는 OPTIONS 메서드를 통해

다른 도메인의 리소스로 HTTP 요청을 보내 실제 요청이 전송하기에 안전한지 확인합니다.

Cross-site 요청은 유저 데이터에 영향을 줄 수 있기 때문에 이와 같이 미리 전송합니다.

간단한 플로우 차트로 나타내 보면 이런 느낌입니다.

프론트단에서 브라우저에게 리소스를 받아오라는 명령을 내리면 브라우저는 서버에게 예비 요청을 먼저 보내고,

서버는 이 예비요청에 대한 응답으로 현재 자신이 어떤 것들을 허용하고, 어떤 것들을 금지하고 있는지에 대한

정보를 응답 헤더에 담아서 브라우저에 다시 보내주게 됩니다.

이후 브라우저는 자신이 보낸 예비 요청과 서버가 응답에 담아준 허용 정책을 비교한 후

이 요청을 보내는 것이 안전하다고 판단되면 같은 엔드포인트로 다시 본 요청을 보내게 됩니다.

이후 서버가 이 본 요청에 대한 응답을 하면 브라우저는 최종적으로 이 응답 데이터를 프론트단에 넘겨줍니다.

OPTIONS 헤더의 용도

그럼 OPTIONS 는 무엇일까요?

HTTP OPTIONS method 는 목표 리소스와의 통신 옵션을 설명하기 위해 사용됩니다.

클라이언트는 OPTIONS 메소드의 URL을 특정지을 수 있으며, aterisk(*) 를 통해 서버 전체를 선택할 수 있습니다.

OPTIONS 메소드를 통해 Prefilght Request (preflight, 사전 전달),

즉 사전 요청을 보내 서버가 해당 parameters를 포함한 요청을 보내도 되는지에 대한 응답을 줄 수 있게 합니다.

Access-Control-Request-Method 헤더는 프리플라이트 요청의 일부분으로 서버에게 실제 요청이 전달 될 때

POST 요청 메소드로 전달될 것 임을 명시합니다.

Access-Control-Request-Headers 헤더는 서버에게 실제 요청이 전달될 때 X-PINGOTHER 와 Content-Type custom headers 와 함께 전달될 것 임을 명시합니다.

서버는 그럼 이러한 요구사항들에 맞춰 요청을 수락할 것인지 정할 수 있습니다.

allowCredentials 설정의 용도

CORS는 기본적으로 보안상의 이유로 쿠키를 요청으로 보낼 수 없도록 막고 있습니다.

하지만 다른 도메인을 가진 API 서버에 자신을 인증해야 정상적인 응답을 받을 수 있는 상황에서는

쿠키를 통한 인증이 필요합니다.

이를 해결해주는 것이 바로 credentials 입니다.

credentialed request는 HTTP Cookie와 HTTP Authentication 정보를 인식할 수 있게 해주는 요청입니다.

요청 시 xhr.withCredentials = true를 지정해서 Credential 요청을 보낼 수 있고,
서버는 Response Header에 반드시 Access-Control-Allow-Credentials: true를 포함해야 합니다.

또한 Access-Control-Allow-Origin 헤더의 값에는 *가 오면 안되고

http://test.test 과 같은 구체적인 도메인이 들어와야 합니다.

profile
코린이

0개의 댓글