DRF 쿠키 samesite

강태원·2024년 4월 22일
0

문제상황

프론트와 로그인 기능 관련해서 API 연동 중에 도메인이 다름에 따라서 쿠키가 전달이 잘 안 됐다.

Chrome
기본적으로 크롬에서는 쿠키의 samesite 설정을 "Lax"로 해놓기 때문에 현 상황에서는 samesite를 None으로 지정해줄 필요가 있다!

첫 번째 코드

response.set_cookie(
                    "access", response.headers.get("access", None), httponly=True, samesite=None, secure=True
                )

빠르게 구글링을 통해 set_cookie 부분을 작성했다.
그런데 프론트 측에서 확인해본 결과 cookie의 samesite 속성이 제대로 지정되지 않았다. 크롬에서 기본으로 세팅되는 Lax도 안 되어 있었다는 뜻!

왜 그랬을까요?

이유를 알아보기 위해서 라이브러리를 파고 들어가봅시다.

def set_cookie(
        self,
        key,
        value="",
        max_age=None,
        expires=None,
        path="/",
        domain=None,
        secure=False,
        httponly=False,
        samesite=None,
    ):
        """
        Set a cookie.

        ``expires`` can be:
        - a string in the correct format,
        - a naive ``datetime.datetime`` object in UTC,
        - an aware ``datetime.datetime`` object in any time zone.
        If it is a ``datetime.datetime`` object then calculate ``max_age``.

        ``max_age`` can be:
        - int/float specifying seconds,
        - ``datetime.timedelta`` object.
        """
        self.cookies[key] = value
        if expires is not None:
            if isinstance(expires, datetime.datetime):
                if timezone.is_naive(expires):
                    expires = timezone.make_aware(expires, datetime.timezone.utc)
                delta = expires - datetime.datetime.now(tz=datetime.timezone.utc)
                # Add one second so the date matches exactly (a fraction of
                # time gets lost between converting to a timedelta and
                # then the date string).
                delta += datetime.timedelta(seconds=1)
                # Just set max_age - the max_age logic will set expires.
                expires = None
                if max_age is not None:
                    raise ValueError("'expires' and 'max_age' can't be used together.")
                max_age = max(0, delta.days * 86400 + delta.seconds)
            else:
                self.cookies[key]["expires"] = expires
        else:
            self.cookies[key]["expires"] = ""
        if max_age is not None:
            if isinstance(max_age, datetime.timedelta):
                max_age = max_age.total_seconds()
            self.cookies[key]["max-age"] = int(max_age)
            # IE requires expires, so set it if hasn't been already.
            if not expires:
                self.cookies[key]["expires"] = http_date(time.time() + max_age)
        if path is not None:
            self.cookies[key]["path"] = path
        if domain is not None:
            self.cookies[key]["domain"] = domain
        if secure:
            self.cookies[key]["secure"] = True
        if httponly:
            self.cookies[key]["httponly"] = True
        if samesite:
            if samesite.lower() not in ("lax", "none", "strict"):
                raise ValueError('samesite must be "lax", "none", or "strict".')
            self.cookies[key]["samesite"] = samesite

위 코드는 장고의 HttpResponseBase 클래스의 set_cookie 함수 전문입니다.

인자를 받는 부분에서부터 samesite=None이 default 값이네요. 벌써 쎄하죠?

아래쪽으로 내려와서 samesite에 관련된 부분을 다시 한 번 봅시다.

if samesite:
            if samesite.lower() not in ("lax", "none", "strict"):
                raise ValueError('samesite must be "lax", "none", or "strict".')
            self.cookies[key]["samesite"] = samesite

아하, samesite 속성을 지정해줄 때 None 값으로 넣어서 if문 자체가 통과가 안 됐었네요..

내용을 참고해보니 none을 문자열로 넣어야 했습니다!

참고 (Django Docs)

여기서도 set_cookie에서 samesite를 어떻게 지정해야하는지 나오네요.
역시 공식 독스..

수정 후 코드

response.set_cookie(
                    "access", response.headers.get("access", None), httponly=True, samesite="none", secure=True
                )

간단한 수정으로 문제 해결 완료!

역시 가장 확실한 방법은 공식 docs를 확인하거나 직접 라이브러리를 까보는 것..
알량한 구글링이 아니라 내가 직접 체득하는게 최고다!

profile
가치를 창출하는 개발자! 가 목표입니다

0개의 댓글