[TIL] CORS에러! 무엇인가?

woonie·2022년 2월 13일
0

TIL

목록 보기
30/64

항해 35일차
처음으로 프론트와 함께 프로젝트를 진행중이다.
프론트/백 연결 해보려고 하는데 모두 첫 협업이다보니 예상하지 못한 오류가 많았다.
그중에서 오늘 CORS 오류가 발생했고 CORS가 무엇인지 찾아보고 공부를 해봤다.

CORS란?

CORS(Cross-Origin Resource Sharing)는 교차 출처 리소스 공유라는 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제이다.

즉, 무분별하게 클라이언트가 다른 리소스에 접근하는 것을 막는 보안 이슈이다.

front 서버와 back서버의 주소(포트)가 다르면 cors에러가 발생한다.

로컬에서는 가능한데 웹개발 시 API 서버에 요청을 보낼 때 흔히 발생한다.
중요한 점은 요청을 어디서 보낸 요청은 에러가 발생 하고 안하는지 기준을 명확히 알아야한다.

CORS의 역할

CORS는 막는 것이 아니라 풀어주는 역할이다.
요청을 막는 것은 SOP(Same-Orgin Policy)라는 '동일 출처 정책'이다.
말 그대로 동일한 출처나 URL끼리민 API등의 데이터 접근이 가능하도록 막는 것이고
우리가 겪었던 CORS에러는 해당 요청이 가능하게 하려면 CORS를 허용해달라는 의미다.

CORS는 Cross-Origin Resource Sharing, Same-Origin의 동일 출처의 반대 개념이다.
의미 그대로 '다른 출처간에 리소스를 공유할 수 있도록 하는 것'이다.

즉, 우리가 만든 웹사이트와 서로 다른 출처끼리 정보요청과 반환이 가능하도록 하는것이다.
처음 기본 값은 서로 다른 출처끼리 요청을 주고 받는 것이 불가하도록 되어있다.

합의된 출처들 간에 정상적으로 허용해주기 위해 기준을 충족시키면 리소스가 공유되도록 만들어진 메커니즘이 바로 CORS, 교차 출처 리소스 공유 방식이다.

CORS의 조건

위에서 얘기했던 기준을 충족시키는 것은 바로 요청을 받는 서버쪽에서 해당 요청을 허락할 다른 출처들을 미리 허용해주면 된다.

CORS 옵션을 작성하는 방법을 참고했고,
(https://en.wikipedia.org/wiki/Cross-origin_resource_sharing)
여기에 허용할 사이트들을 작성해주면 지정한 사이트에서는 해당 서버로 얼마든지 HTTP요청을 보낼 수 있다.
누구나 요청을 가능하도록 하려면 와일드카드(*)로 작성하면 된다.

브라우저는 이처럼 다른 출처끼리의 요청이 보내질 때는 요청에 Origin이라는 header를 추가한다.
header는 데이터가 다른 곳으로 전송될 때, 데이터의 맨 앞쪽에 붙은 보충 정보다.
여기에는 받는 쪽의 IP주소, 사용할 프로토콜이나 옵션 등이 담긴다.

header의 Origin항목에는 요청하는 쪽의 scheme,도메인과 포트가 담긴다.

예를 들어서 주소가 아래와 같다면
https://google.com : 8080
https가 scheme, google.com이 도메인, 그리고 뒤에 붙은 : 8080이 포트번호

이 요청을 받은 서버는 답장의 header 부분에 지정된 Access-Control-Allow-Origin 정보를 실어서 보낸다.
만약 우리의 웹사이트가 등록된 상태이면 해당 URL도 들어있을 것이다.

그럼 이제 브라우저에서 이 둘을 비교해서 Origin에 보낸 정보가 똑같이 존재하면 허용을 해주는 방식이다.
Origin에서 보낸 출처값이 서버의 답장 헤더에 담긴 Access-Control-Allow-Origin에 똑같이 존재한다면 안전한 요청으로 간주하고, 응답 데이터를 받아오게 된다.

CORS에서 보내는 요청

토큰 등의 사용자 식별 정보가 담긴 요청에 대해서는 보다 엄격하게 적용한다.

먼저 보내는 측에서는 요청의 옵션에 'credentials'라는 항목을 true로 세팅해야 하고,
받는 쪽에서도 아무 출처나 다 된다는 와일드 카드가 아니라 보내는 쪽의 출처-웹사이트 주소를 정확히 명시한 다음 Access-Control-Allow-Credentials 항목을 true로 맞춰줘야 한다.
해당 방식은 Simple request 라고 해서 GET이나 POST등 일정 조건의 요청들에 사용되는 방식이다.

W3C 명세에 의하면 브라우저는 먼저 서버에 Preflight request(예비 요청)를 전송하여 실제 요청을 보내는 것이 안전한지 OPTIONS method로 확인한다. 그리고 서버로부터 유효하다는 응답을 받으면 그 다음 HTTP request 메소드와 함께 Actual request(본 요청)을 보낸다. 만약 유효하지 않다면 에러를 발생시키고 실제 요청은 서버로 전송하지 않는다.

이러한 예비 요청과 본 요청에 대한 서버의 응답은 프로그래머가 구분지어 처리하는 것은 아니다. 개발자가 Access-Control- 계열의 Response Header만 적절히 정해주면 Options 요청으로 오는 예비 요청과 GET, POST, PUT, DELETE 등으로 오는 본 요청의 처리는 서버가 알아서 처리한다.

Preflight request는 GET, POST 외 다른 방식으로도 요청을 보낼 수 있고 application/xml처럼 다른 Content-type으로 요청을 보낼 수도 있으며, 커스텀 헤더도 사용할 수 있다.

정리하자면 CORS에서 보내는 요청은 두 종류가 있다.

1) Simple request - GET/ POST 방식

요청은 다 보내기는 하지만, 통과를 못하면 res만 못 받아오는 방식

2) Preflight request - PUT/ DELETE 방식

'요청을 보내는 것'부터 먼저 허락을 받아야 요청을 보낼 수 있는 방식


참고
https://www.popit.kr/cors-preflight-%EC%9D%B8%EC%A6%9D-%EC%B2%98%EB%A6%AC-%EA%B4%80%EB%A0%A8-%EC%82%BD%EC%A7%88/

https://en.wikipedia.org/wiki/Cross-origin_resource_sharing

https://developer.mozilla.org/ko/docs/Web/HTTP/CORS

profile
동료들과 함께하는 개발의 중요성에 관심이 많습니다. 언제나 호기심을 갖고 꾸준히 노력하는 개발자로서 성장하고 있습니다.

0개의 댓글