[Django] 스로틀링(Throttling) - 요청 속도 제어

2024. 1. 12. 08:53Python/Django

목차

    스로틀링(Throttling) 이란?

     클라이언트가 API에 보낼 수 있는 요청 속도를 제어 할 수 있게 해준다. Request가 안정적인 상태의 요청 속도 및 버스트 한도를 초과할 경우, 요청을 실패시키고 "429 Too Many Requests" 오류 응답을 클라이언트에 반환한다. Throttling이 필요한 이유는 시스템에 과부화를 막거나, 악의적으로 과도한 요청을 보내는 공격에 대해서 프로세서를 보호하고 해당 시스템에 과열 문제가 있음을 사용자에게 알리기 위함이다.

     

    Django Throttling 특징

    • 여러 개의 Throttle을 설정해두고, API별로 나누어 설정이 가능하다.
    • 공식 문서에서는 DoS(Denial-of-Service)공격의 방어책으로 사용하지말라고 경고하고 있다.
      • DoS 공격을 방지하고 서비스 가용성을 보호하는데 도움이 될 수 있다.
      • 하지만, 완전한 보호를 제공하지 않기 때문에 추가적인 조치가 필요합니다. 예를 들어 WAS 설정 등
      • 취약점
        • 분산된 DoS 공격에 대한 제한
          • Throttling은 일정한 속도로 요청을 제한하는 방식이기 때문에, 분산된 DoS 공격(Distributed DoS)과 같이 여러 IP 주소에서 동시에 공격하는 경우에는 효과가 제한될 수 있다.
        • 스푸핑(Spoofing) 공격에 취약
          • 스푸핑 공격은 공격자가 IP 주소를 위조하여 공격하는 것을 의미합니다. 이 경우, Throttling은 정상적인 IP 주소로 보이는 요청도 제한할 수 있다.

     

    Django Throttling 설정

    1. 정책 제한 기본 설정

    • DEFAULT_THROTTLE_CLASSES: 전체적으로 해당 Thottle 적용합니다.
      • 추가하지 않아도 무관
    • DEFAULT_THROTTLE_RATES: scope 별 속도 제어를 설정합니다.
      • anon = AnonRateThrottle
      • user = UserRateThrottle
    REST_FRAMEWORK = {
        'DEFAULT_THROTTLE_CLASSES': [
            'rest_framework.throttling.AnonRateThrottle',
            'rest_framework.throttling.UserRateThrottle'
        ],
        'DEFAULT_THROTTLE_RATES': {
            'anon': '100/day',
            'user': '1000/day'
            'burst': '60/min'
        }
    }

    2. Throttle 정의

    class BurstUserRateThrottle(UserRateThrottle):
        scope = 'burst'
       
    
    class BurstAnonRateThrottle(AnonRateThrottle):
        scope = 'burst'

    3. Throttle 적용

     1. APIView 적용

    from rest_framework.response import Response
    from rest_framework.throttling import UserRateThrottle
    from rest_framework.views import APIView
    
    class ExampleView(APIView):
        throttle_classes = [UserRateThrottle]
    
        def get(self, request, format=None):
            content = {
                'status': 'request was permitted'
            }
            return Response(content)

    2. decorator를 이용한 적용

    @api_view(['GET'])
    @throttle_classes([UserRateThrottle])
    def example_view(request, format=None):
        content = {
            'status': 'request was permitted'
        }
        return Response(content)

    3. ViewSet의 @action decorator를 이용한 적용

    @action(detail=True, methods=["post"], throttle_classes=[BurstAnonRateThrottle])
    def example_adhoc_method(request, pk=None):
        content = {
            'status': 'request was permitted'
        }
        return Response(content)

     

    참고