Skip to main content

Lack of protection against brute force attacks - Credentials

Need

Implementation of strong protection against brute force attacks on promotional code credentials

Context

  • Usage of Python 3 for developing applications and scripts
  • Usage of Django for building web applications in Python

Description

Non compliant code

from django.http import JsonResponse
from django.views import View
from .models import PromoCode

class ApplyPromoCodeView(View):
def post(self, request, *args, **kwargs):
promo_code = request.POST.get('promo_code')
try:
promo = PromoCode.objects.get(code=promo_code)
return JsonResponse({'discount': promo.discount}, status=200)
except PromoCode.DoesNotExist:
return JsonResponse({'error': 'Invalid promo code'}, status=400)

This is a simple Django view that accepts POST requests to apply a promotional code. The promotional code is retrieved from the request body using request.POST.get('promo_code'). This code is then used to query the PromoCode model to see if such a promotional code exists. If it does, the discount associated with the code is returned in the response. If it does not, an error message is returned.

The vulnerability here lies in the fact that there is no protection against brute force attacks. An attacker could potentially automate requests to this endpoint with different promotional codes until a valid one is found. This would allow them to get unauthorized discounts. There are no mechanisms in place to limit the number of requests a user can make, no CAPTCHA to verify if the requests are automated or not, and no account lockouts after a certain number of failed attempts. This makes the application susceptible to brute force attacks.

Steps

  • Implement a rate limiting mechanism to limit the number of requests a user can make within a certain time period.
  • Use a CAPTCHA to prevent automated scripts from making requests.
  • Implement account lockout policies after a certain number of failed attempts.
  • Use a delay mechanism to slow down the rate of requests after each failed attempt.
  • Consider using a third-party service that specializes in protecting against brute force attacks.

Compliant code

from django.http import JsonResponse
from django.views import View
from .models import PromoCode
from django.core.cache import cache
from django.conf import settings
import time

class ApplyPromoCodeView(View):
def post(self, request, *args, **kwargs):
ip = request.META.get('REMOTE_ADDR')
promo_code = request.POST.get('promo_code')
attempts = cache.get(ip, 0)
if attempts > settings.MAX_ATTEMPTS:
return JsonResponse({'error': 'Too many attempts. Please try again later.'}, status=429)
try:
promo = PromoCode.objects.get(code=promo_code)
cache.set(ip, 0)
return JsonResponse({'discount': promo.discount}, status=200)
except PromoCode.DoesNotExist:
cache.set(ip, attempts + 1, settings.ATTEMPT_TIMEOUT)
time.sleep(attempts * settings.DELAY_FACTOR)
return JsonResponse({'error': 'Invalid promo code'}, status=400)

The updated code now includes a rate limiting mechanism to protect against brute force attacks. This is achieved by using Django's caching framework to store the number of failed attempts made by a user, identified by their IP address.

When a POST request is made to apply a promo code, the user's IP address is retrieved and the number of failed attempts associated with this IP is fetched from the cache. If the number of attempts exceeds the maximum limit defined in the settings, a 429 response (Too Many Requests) is returned.

If the promo code is valid, the number of failed attempts for this IP is reset to 0 in the cache and a successful response is returned.

If the promo code is invalid, the number of failed attempts for this IP is incremented by 1 in the cache and a delay is introduced before returning a response. The delay increases linearly with the number of failed attempts, which slows down the rate of requests and makes brute force attacks less feasible.

Please note that this is a basic implementation and might not cover all edge cases. For more robust protection, consider using a CAPTCHA, account lockout policies, or a third-party service specializing in protecting against brute force attacks.

References