[ Web ] CORS 동작원리

꾸개·2024년 5월 15일
0

Web

목록 보기
1/3
post-thumbnail

CORS

Cross-Origin-Resource-Sharing의 약자로 교차 출처 리소스 공유를 방지하는 정책이다.

기본적으로 브라우저는 SOP(Same Origin Policy)을 따른다. 여기서 Origin은 URL이라고 생각하면 된다. 따라서 동일한 출처 즉, URL내에서 리소스 공유가 이루어져야 한다는 정책이다. 모든 URL 요청에 대한 응답을 하게 된다면 악의적인 요청으로 정보를 빼낼 수 있어 보안상의 위험이 생기므로 SOP정책이 생겼다고 볼 수 있다.

이러한 정책 때문에 클라이언트 URL과 서버 URL이 다르다면 브라우저에서 발생 시킨다. 보통 프론트엔드는 로컬 URL과 배포된 URL에서 작업하게 되는데 이 때 서버의 URL과 다르기 때문에 CORS에러가 자주 발생한다.


해결법은?

프론트엔드에서는 프록시 서버를 이용해서 중개를 통해 요청과 응답을 같은 URL로 우회해서 하는 방법이 있다. 하지만, 이는 근본적인 해결법은 아니므로, 백엔드에서 배포시에 Access-Control-Allow-Origin에서 프론트 URL을 등록해주는 방식으로 해결 할 수 있다.

//package.json
{
	"proxy": "https://velog.com/joshyeom"
}
// 리액트와 같은 라이브러리들은 proxy를 제공하므로 간단하게 해당 url을 우회할 수 있다.

CORS의 동작원리

요청만 보냈다고 CORS가 동작하는 것은 아니다. 크게 세 가지의 시나리오에 따라 변경된다.

Preflight Request (예비 요청)

브라우저는 요청을 보낼 때 한번에 바로 보내지않고, 먼저 예비 요청(Preflight Request)을 보내 서버와 잘 통신되는지 확인한 후 본 요청을 보낸다.

이 과정은 예비 요청을 통해 간단하게 요청이 안전한지 확인하고 불안전하다면 본 요청을 보내지 않을 수 있다. 따라서 요청 body 데이터가 많은 경우에는 연산을 줄일 수 있기 때문에 도움을 줄 수 있다.

Preflight Request는 GET, POST 요청이 아닌 OPTIONS요청을 사용한다. 이 요청은 따로 설정할 필요없이 브라우저가 자동으로 요청 보낸다.

하지만, 이 자동기능은 오히려 서버와의 통신을 두 번하므로 성능에 영향을 미칠 수 있다. 이를 위해 Access-Control-Max-Age헤더에 캐시될 시간을 명시해 주면, 이 Preflight 요청을 캐싱 시켜 최적화를 시켜줄 수 있다.

Simple Request (단순 요청)

말 그대로 예비 요청을 생략하고 바로 서버에 직행으로 본 요청을 보낸 후, 서버의 응답 헤더에 Access-Control-Allow-Origin을 보고 브라우저가 CORS정책 위반 여부를 검사하는 방식이다.

특정 조건을 만족하는 경우에만 단순 요청을 보낼 수 있는데,
1. 요청의 메소드는 GETHEADPOST 중 하나여야 한다.
2.AcceptAccept-LanguageContent-LanguageContent-TypeDPRownlinkSave-DataViewport-WidthWidth 헤더일 경우 에만 적용된다.
3. Content-Type 헤더가 application/x-www-form-urlencoded, multipart/form-data, text/plain중 하나여야한다.

하지만 이러한 조건을 충족되는 상황은 드물기 때문에 사용될 확률이 적다. 따라서 웬만한 요청은 Preflight로 이루어진다고 이해하면 된다.

Credentialed Request (인증된 요청)

세션 ID가 저장되어있는 쿠키나 Authorization 헤더에 설정하는 토큰 값과 같은 자격인증 정보를 실어 요청할때 사용되는 요청이다.

credentials 옵션을 추가해서 요청을 해야한다. 어떤 메서드를 사용하느냐에 따라 각 라이브러리마다 옵션을 지정하는 문법이 다르다.

fetch("https://example.com:1234/users/login", {
	method: "POST",
	credentials: "include", // 클라이언트와 서버가 통신할때 쿠키와 같은 인증 정보 값을 공유하겠다는 설정
    body: JSON.stringify({
        userId: 1,
    }),
})
// fetch의 경우 includes를 사용한다.

응답의 Access-Control-Allow-Origin 헤더가 와일드카드
(*)가 아닌 분명한 Origin으로 설정되어야 하고, Access-Control-Allow-Credentials 헤더는 true로 설정되어야 한다는 뜻이다. 그렇지 않으면 브라우저의 CORS 정책에 의해 응답이 거부된다.

참고: https://inpa.tistory.com/entry/WEB-%F0%9F%93%9A-CORS-%F0%9F%92%AF-%EC%A0%95%EB%A6%AC-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95-%F0%9F%91%8F
https://velog.io/@wjdwl002/CORS%EC%9D%98-%EA%B8%B0%EB%B3%B8-%EA%B0%9C%EB%85%90%EA%B3%BC-%EB%8F%99%EC%9E%91-%EB%B0%A9%EC%8B%9D%EB%B6%80%EC%A0%9C-Preflight-%EC%9A%94%EC%B2%AD%EC%9D%B4%EB%9E%80

profile
내 꿈은 프론트 왕

0개의 댓글