CORS

이제우·2023년 11월 12일
0

CORS에 대해서

출처(Origin)

먼저 출처의 개념을 이해하고 가야하는데 여기서 말하는 출처란
프로토콜+도메인+포트를 합친 부분이다.

내 벨로드의 url이 https://velog.io/@now-0o로 보자면
https:// (포트), velog.io(도메인), :80(웹 기본포트)가 같아야 동일 출처가 된다.

SOP와 CORS

SOP(Same Origin Policy)동일 출처 정책CORS(Cross Origin Resource Sharing)은 긴밀한 관계를 가지고 있다.

먼저 SOP:동일 출처 정책은 다른 Origin으로 요청을 보낼 수 없게하는 브라우저의 기본 정책이다. 때문에 다른 Origin으로 요청을 보내는 것은 불가능 했지만 세월이 지나고 다른 Origin으로 요청을 해야할 상황이 많아지자 예외의 상황을 두고 다른 Origin으로 요청을 보낼 수 있게 되었다.

  1. <script> 태그로 자바스크립트를 실행하는 경우.
  2. <link> 태그로 스타일시트를 불러오는 경우.
  3. HTTP 문서를 화면으로 보여주는 경우.
  4. CORS 정책을 지키는 요청을 하는 경우.

이렇게 CORS는 우리의 요청을 막는 것이 아닌 동일 출처 정책에서 예외로 요청을 풀어주는 정책이였다.

CORS는 브라우저 정책이기 때문에 서버에서 응답을 하지 않는 것이 아니다.
서버는 정상적으로 응답을 보내지만 브라우저에서 안전한지 판단하고 위험하다가 판단되면 요청은 버려지게 된다.

왜 동일 출처 정책이 필요할까

동일 출처 정책으로 허용되지 않은 요청을 막지 않는다면?
만약 해커가 만든 사이트에 접속할 경우 사용자 개인정보를 빼내는 요청이 보내질 것이다. 사용자는 웹 사이트에 접속 한번 했을 뿐인데 브라우저에 저장되어 있던 사용자의 정보는 이미 해커에게 들어갔을 것이다.

CORS 동작원리

그렇다면 CORS는 어떻게 동작하는 것일까?

  1. 브라우저에서 요청을 보낼 때 헤더 중 Origin 헤더에 자신의 출처를 담아서 보낸다.
  2. 서버는 응답 헤더 중 Access-Control-Allow-Origin 헤더에 허용되는 origin을 담아서 보낸다.
  3. 서버의 응답을 받으면 Access-Control-Allow-Origin 헤더에 브라우저에서 담은 Origin이 포함되어 있는지 확인한다.

결국 CORS 해결은 서버가 응답을 할 때 Access-Control-Allow-Origin 헤더에 Origin을 설정하거나 *(전체)를 설정하면 된다.


CORS의 3가지 동작

CORS에 대해 더 깊게 들어가면 CORS 정책은 3가지 방식으로 나누어서 설명해야한다.

  1. 단순 요청(Simple request)
  2. 예비 요청(Preflight request)
  3. 인증된 요청(Credentialed request)

단순요청

단순 요청은 위의 CORS의 동작원리와 동일하게 예비 요청없이 서버에 바로 요청을 보내는 방법이다. 서버로부터 응답이 오면 브라우저에서 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중 하나여야만 한다.

보통의 요청은 application/json이나 text/xml로 통신하기 때문에 대부분의 API 요청은 예비 요청으로 이루어진다.

예비 요청

예비 요청은 바로 서버에 요청을 보내지 않고 요청이 유효한지 예비 요청을 보낸 뒤 본 요청을 보내는 방법이다. 이러한 예비 요청을 Preflight라고 하며 HTTP Method는 OPTIONS를 사용한다.

먼저 브라우저에서 예비요청을 보낼 때
1. Origin에 출처를 담는다.
2. Access-Control-Request-Method에 실제 요청에 사용할 메소드를 담는다.
3. Access-Control-Request-Headers에 실제 요청에 사용할 헤더를 담는다.

이렇게 요청을 받은 서버는
1. Access-Control-Allow-Origin에 허용할 출처를 설정한다.
2. Access-Control-Allow-Methods에 허용할 메소드를 설정한다.
3. Access-Control-Allow-Headers에 허용할 헤더들을 설정한다.
4. Access-Control-Allow-Age에 이 예비요청이 브라우저에 캐시될 수 있는 초단위를 설정한다.

마지막으로 브라우저는 보낸 예비요청과 받은 응답을 비교하여 안전한지 확인 후 본 요청을 보낸다.

인증 요청

인증 요청은 클라이언트에서 서버에게 자격 인증 정보(Credential)를 담아서 보낼 때 사용한다. 이때 자격 인증 정보는 session id가 저장된 cookieAuthorization 헤더에 담은 토큰을 의미한다.

보통 브라우저에서 제공하는 요청 API는 cookie나 인증 데이터를 담을 수 없다. 그래서 이런 인증 데이터를 담을 때에는 credentials이라는 옵션을 사용해야 한다. 이 credentials는 3가지 값을 사용할 수 있다.

설명
same-origin(기본값)같은 출처 간의 요청일때만 인증 정보만 담을 수 있다.
include모든 요청에 인증 정보를 담을 수 있다.
omit모든 요청에 인증 정보를 담을 수 없다.

이런 정보를 설정하지 않으면 쿠키나 인증정보는 서버로 보내지지 않는다.

서버에서도 인증 요청은 다르게 대응해야 하는데
1. Access-Control-Allow-Credentials에 true를 설정해야 한다.
2. Access-Control-Allow-Origin에 *값을 사용할 수 없다.
3. Access-Control-Allow-Methods에 *값을 사용할 수 없다.
4. Access-Control-Allow-Headers에 *값을 사용할 수 없다.

즉 Access-Control-Allow-Credentials를 true로 설정해준 뒤
응답 Access-Control-Allow-Origin 헤더에 분명한 값이 설정되어야 한다는 것이다.

profile
게으른 사람 중에 제일 부지런하게 사는 사람이 꿈

0개의 댓글