SHOOT - cors에러

민경찬·2023년 2월 10일
0

백엔드

목록 보기
1/22
post-thumbnail

서론


http://api.슛.site로 api를 불러 사용하기로 했다. 그런데 쿠키가 같이 전송되지 않는다.

이 문제가 발생하기까지의 과정과 해결 과정을 적어보려한다.


본론


1. cors에러란?

출처가 다르면 브라우저가 막는 정책, 근데 이제 개발자는 그걸 몰라서 발생되는 것

출처가 다른 요청과 응답에 대해 브라우저가 막는 것을 말한다. 그런데 이 막는다는 것은 브라우저의 역할이다. 이 까다로운 정책은 보안에 도움이 된다. 그런데 개발자는 고생이다. 이 까다로운 정책의 규칙을 조금 둘러보며 쿠키가 안갔던 이유를 자세하게 살펴보자.

2. 문제 과정

1) html서브 서버와 api서버의 분리

프론트 서버와 api 서버를 분리시킨데에는 두 가지 이유가 있다,

  1. GET 요청에 대한 api가 우연히 겹쳐버릴 수도 있다.
  2. DB서버도 api서버에 있는데 api서버에 너무 많은 것이 몰려있는 것 같다.

위와 같은 이유로 분리했다. 그런데 이유모를 에러가 발생하기 시작했다.

2) cors 에러

cors에러가 발생헀다. 브라우저 정책상 도메인이 서로 다르니 "너 이거 뭐야? 둘이 다른데 안전한거 맞아?"해서 잘렸다. 에러도 뱉어줬다. cors 정책을 벗어났단다... 해결책은 너무 간단했다.

app.use(cors());

cors라이브러리를 설치하고 미들웨어로 넣어준다. 지금이 배포 단계가 아니기 때문에 모든 도메인에 대해서 허용해주었다.

그런데 다른 문제가 발생했다.

cors는 서로 다른 출처에 대해서 막는 보안적인 행위입니다. 위 코드처럼 다 허용해버리는 것은 보안에 안 좋겠지요. 배포때만 변경하도록 합시다.

3) 쿠키 전송 안됨

이제 api는 잘 요청된다. 게시글 데이터도 잘 들어온다. 그런데 로그인 api를 테스트 하려고 하니 자꾸 쿠키로 토큰이 발급이 되지 않았다.

혹시 몰라 발급된 토큰을 직접 받아와서 프론트에서 쿠키로 만들어 준 후에 로그인 권한 필요한 api를 호출해봤다. 그런데 자꾸 401응답이 왔다.

401이라고 하면 로그인이 되지 않았다는 것이다. 그래서 원인을 확인해보니 서버쪽으로 쿠키 자체가 전송되지 않았다. 요청 헤더와 응답 헤더 모두 쿠키에 흔적을 찾아볼 수 없었다.

https://wangmin.tistory.com/46

위 블로그에서 힌트를 얻었다. fetch로 요청할 때는 기본적으로 쿠키를 주지 않는다고 한다. 그럼 이 문제는 어떻게 해결할까?

4) credentials : 'include' 옵션 추가

fetch('http://슛.site/log/all', {
    credentials : 'include'
});

fetch함수를 사용할 때 옵션을 위와같이 주게되면 쿠키를 전송하고 받을 수 있다고 한다. 그래서 해봤다. 그런데 이번엔 다른 문제가 발생했다. 서버 측에서 모든 도메인을 허용한 경우 위와 같은 옵션을 사용하더라도 브라우저는 에러를 뱉어준단다.

5) cors 도메인 지정

app.use(cors(corsOption));

corsOption객체에 허용할 도메인을 넣어주었다. 그러자 cors에러는 완벽히 사라졌다. 그런데 여전히 쿠키는 전달되지 않는다. 그래서 하루동안 열심히 고민해보았다. 이것저것 찾아도 보았고 말이다.

3. Https로 바꾸기

쿠키는 secure옵션으로 http가 아닌 https프로토콜에서만 전송되게 할 수 있다. 

여러 사이트를 돌아다녔고 위와 같은 문구를 봤다. 그러자 문득 어떤 생각이 떠올랐다.

  • 크롬이 의도적으로 막는 것 아닐까? 내 api서버는 SSL인증서가 없으니...

크롬은 예로부터 http로 페이지를 전달받으면 아주 광기를 일으키는 브라우저였다. 보안이 어쩌구 정보가 털릴 어쩌구 경고를 페이지 접속전에 대문짝만하게 띄워주고 사용자에게 페이지에 접근하지 않도록 권유했다.

참고로 postman에서 테스트하면 잘 돌아갑니다.

경우의 수

  1. 프론트 서버만 https면 됨
  2. api 서버만 https면 됨
  3. 둘다 http이어야 됨

https로 바꾸는걸 테스트하는 김에 위 경우의 수 모두 테스트해보자.

1) 프론트 서버만 https

  • 결론적으로 안 된다.
    https에서 index.html받았는데 api 서버는 왜 http냐? 라고 한다.

2) api 서버만 https

token2는 프론트에서 직접 발급한 쿠키이고 token은 서버에서 발급한 쿠키이다. 잘.된.다. 프론트 서브도 https로 바꿔서 해봤는데도 잘 된다.

둘다 https일 필요는 없네요 다만 서버 코드에서 cors 라이브러리로 둘다 뚫어줘야하기도 하고 크롬에서 자꾸 털릴 수도 있다고 겁주니까 둘다 https로 바꿔야겠네요.


결론


api서버는 무조건 SSL인증서를 사용하도록 하자!

개발 단계에서는 쿠키 옵션으로 sameSite None을 주는 것으로 해결하는 것도 좋을 것 같네요



참고

0개의 댓글