[TIL] CORS란 무엇인가

박먼지·2023년 6월 5일
0
post-thumbnail

해커톤 프로젝트를 진행하던 중에 권한이 필요한(로그인 상태) api를 요청해야 하는 일이 있었다.

http 통신으로는 axios를 쓰고 있었다.

cookie로 jwt토큰을 보내야 해서, 브라우저-애플리케이션-쿠키 탭에 냅다 cookie를 박아넣었다.

그런데 요청 헤더에 Cookie가 들어있지 않은 것이였다..!

그래서 코드 상에다가 cookie를 하드 코딩으로 집어 넣었다.

  headers: {
    "content-type": "application/json;charset=UTF-8",
    accept: "application/json",
    cookie:"jwt_token=ASDJLKAS...",
  },

그런데 이렇게 넣으니까

xhr.js:200 Refused to set unsafe header "cookie"

안전하지 않다고 거절당했다 😭

자바스크립트는 안전상의 문제로 헤더에 cookie를 넣을 수 없다고 한다.

그래서 쿠키를 첨부해서 보내는 요청인 withCredentials: true로 줬더니

CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

지긋지긋한 CORS 에러가 떴다...!!!

Access-Control-Allow-Origin: * 인 경우 Origin의 제한없이 요청하고 결과를 읽을 수 있는데 이러한 경우 쿠키를 제거하고 요청하도록 정책이 구성되어 있어서 인증 정보를 포함한 요청에서는 불가능하다고 한다.

내가 cookie를 포함한 상태에서 요청했기 때문에 저 에러가 떴던 것이다!

CORS 에러를 해결하려면 CORS에 대해 잘 알아야 할 필요가 있다.. 그래서 하나하나 공부해보기로 했다.

CORS란?
Cross-Origin Resource Sharing의 줄임말로, 다른 Origin(출처)의 리소스 공유에 대한 허용/비허용 정책을 말한다.

Origin, 출처가 무엇일까?

출처는 서버의 위치를 찾아가기 위해 필요한 Protocol과 Host, 포트 번호를 합쳐놓은 것을 말한다.
예를 들어, https://naver.com:80 을 예시로 들면, https는 프로토콜, naver.com은 호스트명, 80은 포트이다.

다른 출처의 리소스 공유를 왜 막는걸까?

생각해보면 간단한 것 같다. 애초에 현재 프로젝트에서 사용자 로그인 정보인 jwt 토큰을 쿠키로 저정하고 전송하는데, 다른 출처의 리소스 공유가 허용된다면 악의적인 사용자가 우리 어플리케이션에 접근해서 jwt 토큰을 빼와서 악용할 가능성이 있는 것이다.

CORS는 어떻게 동작할까?

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

Origin: https://naver.com

이후 서버가 이 요청에 대한 응답을 할 때 응답 헤더의 Access-Control-Allow-Origin이라는 값에 “이 리소스를 접근하는 것이 허용된 출처”를 내려주고, 이후 응답을 받은 브라우저는 자신이 보냈던 요청의 Origin과 서버가 보내준 응답의 Access-Control-Allow-Origin을 비교해본 후 이 응답이 유효한 응답인지 아닌지를 결정한다.

CORS 요청의 종류

브라우저는 CORS 요청 내용을 분석하여 Simple/Preflight, Credential/Non-Credential의 조합 중 해당하는 방식으로 서버에 요청을 날린다.

Simple Request

단순 요청은 서버에게 한번 본 요청을 보낸 후 서버가 이에 대한 응답의 헤더에 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만 허용된다.

Preflight Request

단순 요청 조건에 해당하지 않으면 브라우저는 Preflight Request(예비 요청) 방식으로 요청한다.
Preflight Requests는 브라우저에서 본 요청을 보내기 전에 요청을 보내는 것이 안전한지 확인하기 위해 예비 요청을 보내는 방식을 말한다.

Preflight Requests는 OPTIONS 메소드를 사용한다.

Preflight Request는 다음과 같은 방식으로 동작한다.

OPTIONS /products/ HTTP/1.1
Host: api.domain.com
Origin: https://www.domain.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Authorization, Content-Type

서버는 허용된 메소드 및 헤더를 지정하여 응답한다.

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://www.domain.com
Access-Control-Allow-Method: GET, POST, OPTIONS, PUT
Access-Control-Allow-Headers: Authorization, Content-Type
Content-Type: application/json

헤더와 메소드가 통과되면, 브라우저는 원래 CORS 요청을 보낸다.

POST /products/ HTTP/1.1
Host: api.domain.com
Authorization: token
Content-Type: application/json
Origin: https://www.domain.com

응답은 Access-Control-Allow-Origin 헤더에 올바른 출처가 있으므로 검사를 통과한다.

Request with Credential

HTTP Cookie와 HTTP Authentication 정보를 인식할 수 있게 해주는 요청을 말한다.
요청 시 xhr.withCredentials = true를 지정해서 Credential 요청을 보낼 수 있고, 서버는 Response Header에 반드시 Access-Control-Allow-Credentials: true를 포함해야 하고, Access-Control-Allow-Origin 헤더의 값에는 구체적인 도메인이 와야 한다.
만약 Credentials 옵션은 true로 줬는데 Access-Control-Allow-Origin의 값을 ' * '로 주면 에러가 발생한다.

Request without Credential

CORS 요청은 기본적으로 Non-Credential 요청이므로, xhr.withCredentials = true를 지정하지 않으면 Non-Credential 요청이다.

CORS를 해결하는 방법

1. Access-Control-Allow-Origin 세팅하기

CORS 정책 위반으로 인한 문제를 해결하는 가장 대표적인 방법은, 서버에서 Access-Control-Allow-Origin헤더에 알맞은 값을 세팅해주는 것이다.
Access-Control-Allow-Origin: https://www.example.com와 같이 출처를 명시해주자.

2. 웹 브라우저 실행 옵션이나 플러그인을 통한 동일 출처 정책 회피하기

동일 출처 정책은 브라우저에서 임의로 하는 것이기 때문에 브라우저에서 동일 출처 정책을 사용하지 않으며 된다.

3. jsonp 방식으로 json 데이터 가져오기

자바스크립트 파일이나 css 파일은 동일 출처 정책에 영향을 받지 않고 가져올 수 있다.
이를 이용해서 자바스크립트 파일을 가져와서 이를 json 형식으로 파싱해서 데이터를 사용할 수 있다.

참고
https://bohyeon-n.github.io/deploy/web/cors.html
https://evan-moon.github.io/2020/05/21/about-cors/
https://brownbears.tistory.com/336

profile
개발괴발

0개의 댓글