프로젝트

[Decoupled Architecture] CORS

sian han 2022. 12. 7. 09:58

※ CORS (Cross-Origin Resource Sharing)

추가 HTTP 헤더를 사용하여

한 출처에서 실행중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제

 

 

 

▶ 출처의 구분

어떤 조건에서 출처(Origin) 이 같다고 판단되어 CORS 에러가 발생되는걸까 ?

URL 의 구성요소 중 Scheme, Host, Port 3가지가 동일하면 Origin 이 같으면 같은 출처로 인정된다.

 

 

ex) http://localhost 를 예시로

 

Scheme = http://

Host = localhost

Port = 80(생략되어있음)

 

https://localhost > port 가 다름 (443)
http://127.0.0.1 > 127.0.0.1 은 localhost 이지만 브라우저는 value 로 식별을 하기 때문에 출처가 다르다고 판단됨
http://localhost:80 > 출처가 같음
http://localhost/api/cors > 출처가 같음

 

 

▶ CORS 의 동작

 

클라이언트가 다른출처의 리소스를 요청할 때     ex ) 분리되어있는 서버에 데이터를 요청 

HTTP 프로토콜을 사용해 요청을 보내는데, 이때 브라우저는 Request Header 의

Origin 이라는 프로퍼티에 출처를 담아 보낸다. 

요청한 출처는 로컬 3000 포트에서 작동하는 리액트 서버이다.

Origin 프로퍼티에 이 출처가 잘 담있는 것을 확인할 수 있다. 

 

 

이후 서버가 요청에 대한 응답을 할 때

Response Header 의 Access-Control-Allow-Origin 프로퍼티에

접근허용된 출처 정보를 내려준다.

Response Header는 4000번 포트에서 작동하는 서버가

모든 출처의 접근을 허용한다는 정보를 담고있다 (*)

 

 

이후 응답을 받은 브라우저

자신이 보냈던 요청의 Origin 과

서버가 보내준 응답의 Access-Control-Allow-Origin 을 비교해본 후 응답이 유효한지 / 아닌지를 결정한다.

 

이렇듯 CORS 는 브라우저의 메커니즘이기때문에 

브라우저 없이 서버간 통신을 할 때에는 CORS 정책이 적용되지않고,

CORS 에러가 발생해도 서버 로그에서는 정상적으로 응답했다고 남는다.

 

++ Internet Exploreer 브라우저는 출처 비교에 포트를 포함하지 않는다.

 

CORS 에러는 보안상의 이유로 JavaScript 에서 오류에 대한 세부정보를 확인할 수 없으며,

구체적으로 무엇이 잘못되었는지 확인하는 유일한 방법은 브라우저의 콘솔에서 내용을 확인하는 것이다.

 

 

 

 

▶ Preflight Request

웹 브라우저에서는 서버에 요청하려는 경로와 같은 URL 을 보내

요청할 수 있는 권한이 있는지 먼저 확인하며, 이것을 Preflight Request 라고 한다. 

 

Preflight Request 에는 HTTP 메소드 Options 가 사용된다. HTTP Option 메소드는

  • HTTPHeader("Access-Control-Request-Method") : 실체 요청의 메서드
  • HTTPHeader("Access-Control-Request-Headers") : 실체 요청의 추가 헤더
  • HTTPHeader("Origin") : 요청출처

3가지 HTTP request header 을 사용한다.

JavaScript 의 fetch API 를 사용해 브라우저에 요청하면

브라우서는 서버에 Preflight 를 먼저보내고

서버는 Preflight 의 응답으로 어떤것을 허용하는지 Response Header 에 담아 브라우저에 보내준다. 

 

이후 브라우저는 자신이 보낸 예비요청과 서버가 Response Header 에 담아준 정책을 비교하고

요청이 가능하다고 판단되면 서버에 본요청을 보낸다.

이후 서버가 본요청에 대해 응답을 하면 이 응답데이터를 JavaScript 에 넘겨주는 것이다.

 

 

 

 

 

▶ Simple Request

Simple Request 는 Preflight 를 보내지 않고 바로 서버에 본요청을 보낸 후 서버가 이헤 대한 응답의 헤더에

Access-Control-Allow-Origin 정보를 보내주면 그때 브라우저가 CORS 정책 위반 여부를 검사하는 방식이다.

 

Simple request 는 아래의 조건을 만족해야한다.

 

1. 허용된 HTTP Method

GET, POST, HEAD

 

2. 허용된 Header

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

 

3개의 조건을 만족했을 때 Preflight 없이 바로 Simple Request 를 보낼 수 있다.

 

 

 

 

 

▶ Credentialed Request

 

Credentialed Request 는 인증 관련 헤더를 포함할 때 사용하는 요청으로,

다른 출처 간 통신에서 좀 더 보안을 강화하고 싶을 때 사용하는 방법이다.

 

fetch API 는 별도의 옵션 없이는 브라우저의 쿠키 정보나 인증관련된 헤더를 요청에 담지 않는다.

인증과 관련된 정보를 요청에 담을 수 있게 해주는 옵션이 credentials 옵션이다.

 

쿠키나 토큰을 client 에서 자동으로 담아 보내고 싶을 때

클라이언트 : credentials : incldue

서버 : Access-Control-Allow-Credentials : true

 

 

 

 

https://developer.mozilla.org/ko/docs/Web/Security/Same-origin_policy

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

https://www.youtube.com/watch?v=-2TgkKYmJt4&t=628s 

https://evan-moon.github.io/2020/05/21/about-cors/