ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 클라이언트-서버 cookie 사용 문제
    트러블 슈팅 2023. 6. 7. 18:16

    상황

    Jwt 웹 토큰을 사용하면서, RefreshToken은 보안 상의 문제로 Cookie를 통해 프론트 서버로 전송하려고 상황에서 프론트에서 cookie를 사용하지 못하는 에러 상황이 발생했다.

     

    ❗ 초기 Cors 설정

    registry
        .addMapping("/api/**")
        .allowedOriginPatterns("*")
        .allowedMethods("*")
        .allowedHeaders("*")
        .allowCredentials(true);

     

    Set-Cookie

    ResponseCookie refreshTokenCookie = ResponseCookie.from(REFRESH_TOKEN_HEADER, refreshToken)
        .httpOnly(true)
        .maxAge(refreshExpiredTimeMs)
        .build();
    httpServletResponse.addHeader(HttpHeaders.SET_COOKIE, refreshTokenCookie.toString());

    ◼ 백엔드 서버에서 위와 같이 Set-Cookie 헤더에 RefreshToken Cookie를 담아서 응답하면, 브라우저에서는 해당 서버로 요청을 보낼 때마다 HTTP 헤더 Cookie 필드에 응답받은 Cookie 값을 같이 보내게 된다.

     

    원인 

    Same-Site-Policy

    2020년부터 크롬은 SameSite 쿠키를 별도로 신설해, 다른 출처로 부터 전송되는 요청에 대해서 쿠키 전송을 제한하도록 했다.

     

    First-Party Cookie vs Third-Party Cookie

    ◼ 쿠키에 설정된 도메인을 기준으로 First-Party Cookie와 Third-Party Cookie로 나눌 수 있다. 현재 사용자가 접속한 페이지와 쿠키에 설정된 도메인이 일치하는가?

    ◼ 만일 www.example.com에서 사용자의 요청으로 api.example.com 서버에서 쿠키를 응답 받았다면, 두 도메인이 달라 Third-Party Cookie이다.

     

    SameSite 정책은 다음 3가지 중 하나를 선택할 수 있다. (default: Lax)

    ✔ None

    ◼ 다른 출처의 요청(서드 파트 쿠키)에도 쿠키를 사용할 수 있다. 단, Secure 속성을 true로 해야 한다.

    만일, SameSite를 None으로 설정해도 Secure 속성을 false로 하면 쿠키를 사용할 수 없다. 즉, https 설정을 해야 한다.

     

    ✔ Lax

    ◼ 대부분의 서드 파티 쿠키를 전송하지 않지만, 예외적인 케이스에서만 허용한다. (ex, 유저가 링크를 누르거나 리다이렉트를 통해 이동하거나 서버의 상태를 바꾸지 않을 것이라 기대하는 GET 요청...)

    ✔ Strict

    ◼ 오직 동일 출처의 요청에서 생성된 퍼스트 파티 쿠키만을 전송한다.

     

    📒 해결방안

    1. 가장 먼저, 서버에도 https를 적용하기 위해 nginx(프록시 서버)를 사용해서 적용하였다.

     

    2. ResponseCookie 설정

    ResponseCookie refreshTokenCookie = ResponseCookie.from(REFRESH_TOKEN_HEADER, refreshToken)
        .secure(true)
        .httpOnly(true)
        .sameSite("None")
        .maxAge(refreshExpiredTimeSec)
        .build();
    httpServletResponse.addHeader(HttpHeaders.SET_COOKIE, refreshTokenCookie.toString());

    ◼ responseCookie에 secure 속성과 sameSite 속성을 추가하였다.

     

    ◼ 위와 같이 Set-Cookie에 RefreshToken Cookie가 응답으로 잘 오는 것을 확인할 수 있다.

     

    ◼ 위와 같이 Request Header에서도 Cookie에 잘 적용되는 것을 확인할 수 있다.

     

    결론

    💥 프론트, 백 서버를 다른 도메인으로 배포하고 Cookie를 사용하기 위해서는 https를 적용하고 sameSite 정책을 고려해서 사용해야 한다.

     

    🛠 추가로, 프론트에서 withCredentials=true를 설정하고 요청해야 Cookie를 사용할 수 있다. 이 부분으로 인해 많은 삽질을 경험하였다...

     

    💬 Credentials 이란?

    쿠키, Authorization 인증 헤더, TLS client certificates 를 내포하는 자격 인증 정보를 말한다.

    기본적으로 axios 등의 라이브러리를 사용해서 API 요청, 응답을 진행하면, 쿠키와 같은 인증과 관련된 데이터를 함부로 사용하고 받을 수 없다. 이러한 것을 허용해주는 것이 withCredentials=true 옵션이다.

    댓글

Designed by Tistory.