학부 연구를 진행하던 도중, 유저의 로그인 구현에 대해 여러가지 문제를 겪었다. 

 

1. 일단 나의 애플리케이션에서는 SSO를 이용한 CAS를 이용해 로그인을 구현하였다.

2. 하지만 로그인은 보안 인증 문제가 까다롭기 때문에 HTTPS에서밖에 작동하지 않는다. 

 

그래서 HTTPS 프로토콜을 설정하려고 하다 보니, cors옵션을 설정 할 일이 있었다. 사실 그때는 뭐가 뭔지 모르고 그냥 구글링을 통해 얻은 정보로 소스코드만 작성했지만, 오늘 교수님과의 미팅중에 교수님이 내 코드를 보더니 "Why do you have cors options in your server side code? can you explain?" 나는 아무것도 답변할 수 없었다,,, 또 한번 깨달았다. 나는 지금 그냥 막연히 애플리케이션을 개발 - 배포하기보단, 애플리케이션을 개발 - 배포를 하면서 배우는중이라는 사실을 잠깐 망각했다. 그래서! 이번엔 CORS가 뭔지 보고 넘어가도록 하겠다.

CORS란 무엇인가?

CORS(Cross-Origin Resource Sharing)는 출처가 다른 자원들을 공유한다는 뜻으로, 한 출처에 있는 자원에서 다른 출처에 있는 자원에 접근하도록 하는 개념이다. 직역하면, 교차되는 출처 자원들의 공유다. 다른 출처에 있는 자원을 요청한다고 하면, 이를 교차 출처 요청이라고 부른다.

 

예전에는 CORS가 대중적이지 않았다. 하지만, 개발 시장이 빠르게 발전함에 따라, 내가 현재 접속한 애플리케이션에서 다른 애플리케이션과 상호작용할 일이 많아짐에따라 CORS가 등장하게 되었다.

 

더보기

교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제입니다. 웹 애플리케이션은 리소스가 자신의 출처(도메인, 프로토콜, 포트)와 다를 때 교차 출처 HTTP 요청을 실행합니다.

출처 : MDN

즉, CORS는 HTTP 통신을 요청할 때 HEADER에 CORS와 관련된 정보를 추가적으로 입력하여 다른 출처의 자원에 접근할 수 있도록 하는 것이다.

 

먼저, 출처라는 개념을 알아야 한다. 웹에서 '출처'란 무엇일까?

https://beomy.github.io/tech/browser/cors/

 

여기서 어디까지가 같다면 위에서 언급된 "한 출처"라고 할 수 있을까?

위의 요소 중, Protocol + Host + Port 3가지가 같으면 동일 출처(Origin)라고 한다.

 

다음은 다른 블로그에서 잘 정리된 테이블을 통해 간략히 동일, 다른 출처의 예시를 보고 넘어가 보자.

https://escapefromcoding.tistory.com/724

즉, 간단히 같은 출처와 다른 출처를 비교하자면,

  • 같은 출처 : 내가 접속한 사이트와 다른 사이트의 Protocol, Host, Port 가 전부 다 동일
  • 다른 출처 : 내가 접속한 사이트와 다른 사이트의 Protocol, Host, Port 중 하나라도 다른 경우

CORS의 동작 과정

  • CORS는 브라우저에 의해 동작한다
    1. 내가 접속한 사이트 (클라이언트)에서 다른 출처의 사이트 (서버)로 리소스를 얻기 위한 HTTP Request 를 보낸다
    2. 브라우저는 그 사이에서 Request Headers 에 Origin 이라는 필드에 요청을 보내는 출처 (내가 지금 접속하고 있는 사이트)를 보낸다
    3. 서버에서는 이 Request를 받아 Response Headers에 Access-Control-Allow-Origin
      이라는 필드에 접근이 허용되는 출처를 담아 응답한다.
    4. 브라우저는 해당 Response에 Access-Control-Allow-Origin 와 Request에 Origin 을 비교하여 이 응답이 CORS가 허용되는 응답인지 아닌지 결정한다.

자 그럼, 이제 실제 나의 프로젝트에서 Cors를 어떻게 설정 하는지 직접 코드로 확인해 보자.

const corsOptions = {
  origin: 'https://crescendo.cs.vt.edu:3000',
  optionsSuccessStatus: 200,
  credentials: true
};
app.use(cors(corsOptions));

위는 내 server.js의 corsOption을 설정하는 코드이다. 

  • origin : 이 옵션은 cors옵션을 허용할 도메인을 지정한다. 위의 경우, https://crescendo.cs.vt.edu:3000에서 오는 요청만 허용한다. 여러 도메인을 사용하고 싶을 경우, 배열을 사용할 수 있다. 예를들어, 2개의 도메인에서 들어오는 요청을 허용하고싶다면 아래와 같이 설정 할 수 있다.
origin: ['https://crescendo.cs.vt.edu:3000', 'https://anotherdomain.com']

만약, 모든 도메인에서의 요청을 허용하고싶다면, 

app.use(cors());

처럼 corsOptions라는 객체를 만들 필요도 없다.

  • optionSuccessStatus : 프리플라이트 요청(OPTIONS 메서드)에 대한 응답 상태 코드를 지정한다.
    일부 브라우저는 204 상태 코드를 제대로 처리하지 못할 수 있기 때문에, 200 상태 코드로 응답하도록 설정할 수 있다.
    기본값은 204 이지만, 여기서는 200으로 설정되어 있다.
  • Credentials: 클라이언트가 자격 증명(쿠키, HTTP 인증 정보, 클라이언트 SSL 인증서)을 포함한 요청을 허용할지 여부를 설정한다. true로 설정하면 자격 증명 정보를 포함한 요청이 허용된다.이 옵션이 true로 설정되면 Access-Control-Allow-Origin 헤더는 *로 설정할 수 없고, 특정 도메인을 지정해야 한다.

Trouble Shooting

문제 : 클라이언트에서 서버로 POST요청을 보내면 서버는 request를 받지도 않고, 당연히 request도 받지 않으니 response도 없었다. 포트 번호를 잘못 적었나 등등 여러가지를 면밀히 관찰했지만 이유를 찾아낼 수 없어 답답해 하던 도중, corsOption을 다시 봤다. 

 

나의 corseOption에서는 허용 도메인은 딱 하나이다. crescendo.cs.vt.edu:3000. 그런데, 생각해 보니 난 더이상 포트번호 3000번으로 접속 하고있지 않다는걸 깨달았다. 포트 번호를 지우니 POST요청도 정상적으로 받고, 응답도 제대로 해 주었다. 결국 내가 한참을 고민하던 이 문제는 cors때문이였다... 그래도 이 기회에 cors가 뭔지도 배웠으니 만족한다! 만약 여기서 문제가 발생하지 않았다면 난 cors가 뭔지도 모른채 그냥 코드만 찍어내고 말았을것이다. 

+ Recent posts