안녕하세요. 이번에 발견한 문제는 쿠키 관련 문제입니다.
쿠키는 F/E와 B/E에서 사용하는 헤더 값으로, 서버에서 cookie값을 셋팅해서 내려주면
브라우저에서 해당 쿠키값을 저장하고 있는 것입니다.
로그인 관련 고민을 하고 계시거나, 인증, 인가를 고민중이라면 많이 들어보셨을 것입니다.
저 또한, 로그인 관련 문제를 쿠키 값으로 해결하던 와중에 문제가 발생했습니다.
현재 로그인 시 backend에서 쿠키를 특정 session 값으로 내려주도록 설정헀습니다
즉, 해당 세션값과 일치하는 정보를 서버에서 저장하고 있고, 사용자 요청이 왔을 때 세션 값을 통해 인증, 인가 하도록 구현했습니다.
토큰을 사용하지 않고 세션을 이용한 이유는, 세션 정보를 저장할 때 부하가 될 정도로 사용자가 많을 것이라 예상되지 않았고, 이로 인해 토큰 보다는 서버쪽에서 로그인 및 인증, 인가 여부에 대한 권한을 더욱 가져갈 수 있도록 세션을 이용해서 구현했습니다,
쿠키에 값을 저장하고, backend에 요청을 보냈는데 API가 제대로 응답하지 않았습니다.
또한, 인증 및 인가가 필요한 API가 모두 제대로 동작하지 않고 권한 문제가 발생하고 있었습니다.
그럼 어디서 문제가 발생했는지, 하나씩 체크해보기로 했습니다.
backend에서 응답할 때 addCookie를 통해 쿠키를 같이 내려주도록 했지만, 이 부분에서 제대로 동작하지 않는다고 생각했습니다.
이 부분은 크롬의 개발자 도구를 통해 확인했고, backend API를 호출하면 제대로 쿠키 값이 저장되어 있는 것을 확인하였습니다.
즉, 제대로 쿠키 설정을 해서 응답을 했습니다.
확인: B/E 에서 값을 내려줄 때 제대로 cookie 설정을 했음.
Backend에서 로그인과 관련된 세션 값을 저장하고, 캐시 데이터에서 유저 식별 번호와 세션 id를 관리하도록 작성했습니다.
이 값이 제대로 저장되고 있지 않거나, 해당 세션 값으로 유저 정보를 특정할 수 없는 상황일 수 있다고 생각하고, 이를 확인했습니다.
하지만, 캐시에는 유저 정보를 특정할 수 있는 데이터가 제대로 저장되고 있었기 때문에, 제대로 저장되지 않아서 생기는 문제는 아닌 것으로 확인했습니다.
확인: 로그인 시 생성되는 세션 값도 서버에서 잘 저장하고 있음. 캐시 데이터를 저장할 때 문제가 생기는 것이 아님.
여기까지 오니, Request Header에서 해당 값을 제대로 주지 않는 것이라 판단했습니다.
이를 검증하기 위해, B/E서버에서 log를 찍어서 확인했는데, header에서 해당 cookie 값을 확인할 수 없었습니다.
즉, 크롬에서는 제대로 해당 데이터를 가지고 있는데, 이를 B/E에 제대로 전달하고 있지 못했습니다.
확인: Request Header에서 해당 값을 같이 보내지 않음.
여기까지 오니 실마리가 보이기 시작했습니다.
F/E와 B/E의 도메인이 다른 것이 문제가 되는 것이라고 어느정도 추측이 가능했습니다. 도메인을 구매해서 하는 것이 아니라, 각자 프로젝트를 진행하고, 연결하는 작업을 하다보니 인프라 구축이 제대로 되어있지 않았습니다.
3)에서 발견한 문제를 검증하기 위해, 로그인 후 권한이 필요한 API를 직접 호출하니 제대로 동작하는 것을 확인헀습니다.
여기까지 오니 쿠키 설정을 잘못했다는 것도 어느정도 추측이 가능해서 관련하여 문제를 찾아보기 시작했습니다.
검증: Backend로 직접 호출하면 쿠키가 제대로 같이 오는 것 확인.
해당 문제를 해결하면서 쿠키 설정을 보던 중, same site 옵션에 대해 알게 되었습니다.
이 옵션은 chrome 80부터 설정을 해주어야 하는데, 기본 값이 None -> Lax로 변경되었다고 합니다.
same site 값에 따른 속성은 다음과 같습니다.
이 옵션을 None으로 주면서 제대로 쿠키 값을 전달하는 것을 확인했고, 해당 문제는 해결했습니다.
해결: SameSite = None 을 옵션으로 설정.
기존에는 cookie를 만들 때 Cookie 객체를 생성해서 response에 추가하는 방법을 사용했는데,
이번에 만들면서 ResponseCookie 객체를 사용해서 만들었습니다.


위의 사진처럼 javax.servlet.http 에서 제공하는 Cookie 객체에는 same site 값에 대한 필드가 정의되어 있지 않습니다.

이와 반대로 ResponseCookie 에는 이미 sameSite 옵션도 정의되어 있었습니다.
이번 기회에 ResponseCookie에 대한 정보를 알 수 있었고, cookie 설정은 ResponseCookie를 사용하도록 변경했습니다.
추측하기론 javax.servlet은 보수적으로 업데이트가 되지 않았지만, spring 진영은 chrome 반영에 대해 발 빠르게 작업이 된게 아닌가 싶습니다. (매우 주관적인 생각입니다.)
Cookie에서 설정해도 어디선가 sameSite 설정을 하는 방법이 있을텐데, 이 부분은 시간이 되면 이 글 뒷 부분에 추가해서 작성해보겠습니다.
회사에서는 같은 도메인을 사용했지만, 사이드 프로젝트에서 B/E와 F/E 각자 독립적으로 동작하다보니 발생한 이슈네요. 문제 해결때는 힘들었지만, 해결하고 보니 개발자 커뮤니티를 계속 봐야겠다는 교훈도 얻으면서 끝냈습니다.
이와 같이 쿠키에 세션값을 저장하는 방식으로 인증, 인가를 하고 있지만, 더 좋은 방법이 있는지는 생각해봐야 할 것 같습니다. 유저의 쿠키 정보를 다른 사이트에서 사용할 수 있기 때문에 Lax로 기본값을 변경했다고 하는데, 세션값이라 아무 상관 없을지도 모르지만, 도메인이 다를 때 더 안전한 방법이 있는지 계속 고민해봐야 할 것 같습니다.
이 문제를 해결하면서 참고한 사이트는 다음과 같습니다.
긴 글 읽어주셔서 감사합니다. 😁