🌈 프로그래밍/Django

Django Session Cookie Age 알아보고 커스텀하기

반응형

Django 프로젝트의 루트 경로에 있는 settings.py에 정의되어 있는 세션 관련 내용이 다음과 같았다.

  • REST_FRAMEWORK
REST_FRAMEWORK = {

    "DEFAULT_AUTHENTICATION_CLASSES": [
        "rest_framework.authentication.SessionAuthentication",
    ],
}
  • INSTALLED_APPS
INSTALLED_APPS = [
        ...
    "django.contrib.sessions",
        ...
]
  • MIDDLEWARE
MIDDLEWARE = [
        ...
    "django.contrib.sessions.middleware.SessionMiddleware",
        ...
]

API 테스트를 진행하던 도중, 아래와 같은 응답을 받은적이 있었다.

{
    "detail": "자격 인증데이터(authentication credentials)가 제공되지 않았습니다."
}

자격 인증 데이터가 필요한 API 요청을 할 경우에는 해당 유저가 유효한지 Request Cookie 값의 session_idcsrftoken 값을 확인한다.
둘 중 하나라도 유효하지 않다면 위와같은 응답이 오게 된다.

  • 기본적으로 Django의 Session 유효기간을 설정하지 않았다면 아래와 같다.
>>> settings.SESSION_COOKIE_AGE 
1209600

확인하는 방법은 터미널에서 shell_plus를 실행시켜 위의 명령어로 확인이 가능하다.

위 값의 단위는 sec(초)를 의미하며 1209600초는 2주를 의미한다. 따라서 14일로 설정되어 있음을 알 수 있다.

아래와 같이 쿠키 나이 값을 바꿔서 확인이 가능하다.

# settings.py
SESSION_COOKIE_AGE = 180

짧게 설정하고 인증이 필요한 API요청을 한다면 위의 응답을 마주할 것이다. (만약 강제로 리다이렉트 하는 코드가 없다는 가정 하에)

그렇다면 과연 쿠키 나이 값을 2주로 설정하는 것이 바람직한 것일까?

요새 핫한 chatgpt에게 물어보았다.

Q. 일반적으로 유저의 로그인 세션 정보를 유지하는 적절한 기간을 알려줘.

The recommended value for SESSION_COOKIE_AGE depends on the requirements and constraints of your specific Django project. Here are a few things to consider when deciding on a value:

  • User experience: Longer session cookie ages can provide a better user experience by allowing users to stay logged in for longer periods of time. However, shorter session cookie ages can help to improve security by reducing the risk of session hijacking.
  • Security requirements: If your project deals with sensitive information or has high security requirements, you may want to set a shorter session cookie age to reduce the risk of session hijacking.
  • Compliance requirements: Depending on the regulations that your project is subject to, you may be required to set a specific session cookie age. For example, the GDPR requires that users be informed of the duration of any cookies that are used on a website.
  • Technical constraints: Longer session cookie ages can increase the size of your session database, which can impact performance. Additionally, some browsers may have limits on the maximum age of cookies.

With those considerations in mind, a common value for SESSION_COOKIE_AGE is 2 weeks (1209600 seconds). This provides a good balance between user experience and security. However, it's important to evaluate the specific requirements of your project and adjust the value accordingly.

해석해보니 프로젝트의 요구사항과 세션 만료 값을 설정하기 위해 몇가지 고려해야 할 점들을 알려준다.

첫 번째로는 유저 경험 에서 길게 설정된 세션 쿠키값은 더 나은 유저 경험을 제공해줄 수 있다고 한다. 반면, 짧게 설정된 세션 쿠키값은 보안와 관련 즉, 세션 하이재킹 과 같은 문제에 대한 위험을 감소시켜줄 수 있다고 한다.

두 번째로는 보안 요구사항 이다. 만약 프로젝트가 민감한 개인정보 또는 높은 보안 요구사항이 필요하다면, 세션 쿠키 값을 짧게 설정해주어야 한다. 예를 들어 이러한 경험이 있을 것 같다. 은행이나, 공공기관 같은 경우에서는 로그인 만료 시간이라고 상단에 표기되어있고 제한시간이 걸려있는 경우의 페이지를 본 적 있을 것이다! 이게 바로 짧게 설정된 세션 쿠키 값을 활용한 예시라고 볼 수 있다!

세 번째로는 규정 준수 요구사항 이다. 프로젝트가 어떤 규정, 법에 의존하고 있다면 구체적인 세션 쿠키 만료값이 필요하다고 한다. 예를 들어, GDPR은 웹 사이트에서 사용되는 쿠키의 지속 기간을 사용자에게 알릴 것을 요구합니다.

마지막으로 기술적 제약 이다. 유지 기간이 긴 세션 쿠키 값은 세션 DB의 사이즈를 증가시킬 수 있다. 이는 성능에 영향을 줄 수도 있다. 추가로, 몇몇의 브라우저는 가질 수 있는 최대 쿠키 만료 기간이 존재한다.

Django 에서의 기본으로 설정된 SESSION_COOKIE_AGE 는 2주이다. 이는 유저 경험과 보안에 있어서 적절한 밸런스를 제공한다고 한다. 하지만, 본인의 프로젝트에 구체적인 요구사항을 평가하는 것은 중요하고, 그에 따라서 적절하게 값을 변경해야 한다!

(똑똑한 gpt네요..)

그렇다면 각자 프로젝트의 요구사항과 관련한 몇 가지 내용들을 점검해야 한다.

  • 프로젝트가 민감한 개인정보들을 다루고 있고, 개인정보가 중요한가?
  • 프로젝트가 은행, 타 공공기관처럼 보안이 철저해야 하는가?
  • 프로젝트가 특정 규칙 또는 규정을 따라야 하는가?

만약 위의 질문에 모두 "예"라는 답을 할 수 있다면 짧게 설정하는 것이 바람직해 보인다.

하지만, 너무 짧게 제한 시간을 설정한다면? 더 자주 로그인을 해야하는 유저의 불만이 있을 수 있다.

SessionAuthentication을 커스텀해서 Detail 메세지 수정하기

위의 클래스를 수정해서 유저에게 오류가 아니게 알려줄 수 있다.

우선, SessionAuthentication가 어떤 녀석인지 알아볼 필요가 있다.

위에서 살펴봤듯이

"rest_framework.authentication.SessionAuthentication",

를 사용하고 있으니 해당 클래스를 살펴보면 아래와 같다.

class SessionAuthentication(BaseAuthentication):
    """
    Use Django's session framework for authentication.
    """

    def authenticate(self, request):
        """
        Returns a `User` if the request session currently has a logged in user.
        Otherwise returns `None`.
        """

        # Get the session-based user from the underlying HttpRequest object
        user = getattr(request._request, 'user', None)

        # Unauthenticated, CSRF validation not required
        if not user or not user.is_active:
            return None

        self.enforce_csrf(request)

        # CSRF passed with authenticated user
        return (user, None)

    def enforce_csrf(self, request):
        """
        Enforce CSRF validation for session based authentication.
        """
        check = CSRFCheck()
        # populates request.META['CSRF_COOKIE'], which is used in process_view()
        check.process_request(request)
        reason = check.process_view(request, None, (), {})
        if reason:
            # CSRF failed, bail with explicit error message
            raise exceptions.PermissionDenied('CSRF Failed: %s' % reason)

우선, BaseAuthentication 이라는 클래스를 상속받고 있음을 알 수 있었다.

BaseAuthentication 클래스는 필수로 def authenticate 라는 함수를 오버라이드 해야한다.

authenticate 함수는 만약 요청 세션이 현재 로그인 된 유저라면 csrftoken 검증까지 완료되면 유저 객체를 리턴하고 아니라면 None을 리턴한다.

따라서 커스터마이즈 클래스를 하나 만들고, SessionAuthentication 를 상속받아서 def authenticate 함수를 오버라이드해서 아래와 같이 코드를 작성했다.

# custom_authentication.py

from rest_framework.authentication import SessionAuthentication
from rest_framework.exceptions import AuthenticationFailed


class CustomSessionAuthentication(SessionAuthentication):
    def authenticate(self, request):
        user_auth_tuple = super().authenticate(request)
        if user_auth_tuple is None:
            raise AuthenticationFailed("로그인 세션이 만료되었습니다. 다시 로그인해주세요!")
        return user_auth_tuple

authenticate 함수의 반환된 값이 유저가 아니라 None 이 반환된다면 예외를 발생시켜 사용자에게 만료된 팝업을 띄우도록 한다!

그리고 최종적으로 settings.py 의 내용을 커스텀하게 작성한 세션 인증 클래스를 사용하기 위해서 교체한다.

# settings.py

from project.custom_authentication import CustomSessionAuthentication

REST_FRAMEWORK = {
        ...
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "project.custom_authentication.CustomSessionAuthentication",
    ],
        ...
}

그러면 아래와 같이 어떤 인증이 요구되어지는 API를 호출하면 detail을 아래와 같이 출력한다.

 

위의 커스텀 클래스를 적용하면 기존에 접속 가능하던 시크릿 모드에서는 접속이 불가능하다??

파악한 내용이 아직까지는 부족한 것 같았다.

반응형