Skip to content

Cookie 삽질 기록

JinuCheon(깻묵) edited this page Apr 12, 2022 · 1 revision

쿠키삽질

쿠키에 관한 삽질 내용을 정리해보자 한다

먼저 우리 toy 프로젝트 서비스의 로그인 전략은 카카오 소셜 로그인을 사용하였고 프론트는 react CRA를 사용 백앤드는 Spring을 사용하였고 브라우저는 크롬을 사용했다.

카카오의 로그인 방법을 간략하게 소개하면

  1. 유저가 카카오 로그인을 클릭하면 프론트서버가 지정된 URL로 (자세한건 공식문서 참조) 보내 카카오서비스에 로그인을한다
  2. 로그인을 하면 카카오 서버가 자동으로 설정한 redirect url로 url에 인가코드와 합쳐서 redirect 시킨다.
  3. 프론트는 이 url을 parsing해서 백앤드로 인가코드 값을 보낸다
  4. 백앤드는 인가코드를 카카오서버에 토큰을 요청한다
  5. 카카오 서버에서 토큰을 확인하고 주면 쿠키를 생성해 프론트로 넘겨준다

(카카오 공식문서 사진 붙이기)

여기서 문제가 생긴것이 토큰을 확인하고 쿠키를 생성을 잘했지만 프론트로 넘겨주니 에러가 발생한것이다

Untitled

1. Cors Error

cors 에러는 한번 겪어 본적이 있다 Cross Origin Resource Sharing의 약자로 도메인 및 포트가 다른 곳에서 클라이언트가 요청했다는 이유이다

awe 서버를 올려놔서 여기에 요청을 하면 Host 포트번호가 모두 달라 cors 오류가 나는 것이었다 오류가 발생하는 원인은 클라이언트가 직접적으로 서버에 요청을 보내서 제어하려고 하기 때문에 보안 문제로 일어나게 된다 잘 생각을해보면 서버입장에서는 도대체 무엇을 믿고 요청을 받아서 수행한단 말인가? 그게 해커일수도 있는데...

해결법

그럼 간단하다 내가 서버에 직접적으로 제어를 하기때문에 발생하는 것이니 직접적인 제어를 하지 않으면 된다 이것이 첫번째 방법인 proxy방법이다

proxy는 클라이언트와 백앤드사이에 가상의 서버를 놓아서 클라이언트가 직접적으로 서버를 제어하지 못하도록 한다 webpack 의 설정으로 가상의 proxy 서버를 거쳐서 백앤드와 통신을한다.

두번째 방법으로는 응답해더에 Access Control Allow Origin을 사용하는것이다.

설정한 출처에서의 응답을 허용하는 설정이다 서버에서 이것을 세팅해 놓으면 요청을 받을수 있다. CORS 에러가 조금 햇갈렸던게 서버에서 이 응답을 막는것이 아니라 브라우저가 CORS 에러를 발생한다는 점이었다 그래서 서버쪽에서 헤더를 설정해서 보내줘야 브라우저에서 이 헤더를 보고 응답을 받을 수 있다.

단 *(와일드카드)는 모든 요청을 받겠다는 뜻이므로 귀찮더라도 꼭 프론트의 주소로 세팅을하자

2. Cookie 저장 실패(Set-Cookie header didin’t specify a SameSite)

에러를 보면 credentials mode를 include로 바꾸라고 나와있다. RTK-query의 credentials를 include를 바꾸고 실행을 해보니 에러없이 정상적으로 쿠키를 받아올수 있었다

하지만 문제가 있었다 request POST 요청은 잘 받았지만 chrome browser devtools의 Application 에서는 받아온 쿠키를 저장하지 않는것이다 RTK-query를 처음사용하여 문법 문제라 생각하고 하루를 새워 찾아보았지만 credentials를 include로 바꾸라는 글만 찾을수 있었다

그래서 다음전략으로는 header에 있는 쿠키를 직접 저장하자 였다 하지만 가장 어리석었던 방법이고 쿠키를 이해하지 못해서 생긴 전략이었다.

HTTP는 stateless 프로토콜이다 즉 요청을 보내면 그 요청의 사용자가 누구인지 모른다 이 상황에서 로그인을 하고 “나 로그인했어요 데이터 주세요” 하면서 다음 요청을 보내면 서버는 누구인지 기억을 못한다는 것이다 그래서 요청이 누구인지 알수 있게끔 증을 발급해주는게 쿠키이다. 그렇기 때문에 이것이 어디서 탈취 되거나 위조되서는 안되는데 이것이 XSS(Cross-Site Scripting) 공격 스니핑(Sniffing) 공격등등 으로 탈취를 당한다

백앤드 에서도 이를 막고자 쿠키 설정에 HttpOnly를 넣어서 쿠키를 주었는데 이는 javaScript에서 쿠키에 접근 할 수 없게 설정하는 것이다. 설정 자체도 javascript 상에서 조작하지 못하였고 애초에 header에 접근해서 Set-Cookie 값을 가져오는것 부터가 불가능한 일이었다.

samesite issue

계속 에러를 찾아보던중 header에 조그만하게 warning창이 떠져 있는것을 보았다

This Set-Cookie didn't specify a "SameSite" attribute and was default to "SameSite=Lax" ...

열심히 검색을 해본결과 크롬 정책이 SameSite=none 에서 SameSite=lax로 바뀌었기 때문이다 SameSite 는 서브도메인이나 포트번호를 포함하지 않은 도메인을 말한다 기존에 크롬에서는 이 설정이 none여서 서로 다른 도메인에서 요청을 보냈을때 다른 도메인이여도 쿠키가 전송이 되었다 하지만 업데이트 이후 lax 설정으로 바뀌었고 이 lax 설정은 get요청과 같은 일부 케이스만 허용을 하게된것이다 자 백앤드 서버는 aws에 도메인으로 있고 프론트는 local에 있다 따라서 이 samesite에 의해서 쿠키가 전달되었음에도 막혀지게 된것이다

이를 해결하기 위해서는 설명대로 none로 바꿔 주면 된다 .....라고 생각을하였으나 여기서 또 문제가 발생한다 none로 적용을 하려면 secure 옵션을 true로 바꿔줘야 한다 그런데 이 secure옵션을 true로 바꿔버리면 https만 접속이 가능하다 이때까지 만든 프로그램은 local aws 는 전부 http를 쓰고 있었다 프론트와 백앤드를 설정해주면 되긴하겠지만 손이 매우 많이 가는 작업이었다 그래서 다음으로 생각한것이 프론트도 백앤드와 같은 호스트로 배포를 해서 테스트를 하는것이었다 결국은 2번째 방법인 백앤드와 같은 호스트로 배포하였다

4일간 프론트와 백앤드의 삽질이 여기서 종료되었다 중간중간에 자잘한 삽질들도 많았지만 큰 포인트만 써두었다.

기존에 개발 후 서비스를 배포한다는 틀을 깨고 테스트 서버에 배포를 하면서 백앤드도 테스트에 참여할 수 있고 실제 배포 환경에서 벌어질 수 있는 문제들을 사전에 예방할 수 있어서 더 좋았다.

  • 야매방법) etc/hosts 에 테스트 api주소를 박아두고 사용한다 ⇒ 이게 되네....?