Evgenii Legotckoi
9 января 2017 г. 20:45

Django - Урок 018. Блокировка злоумышленников по IP при попытках подбора пароля на Django

Содержание

После того, как мы подменили страницу авторизации Django на свою собственную кастомизированную страницу авторизации , настал момент для использования данной подмены для целей улучшения безопасности сайта. Например, внедрение блокировки злоумышленника по IP при попытке подбора пароля.

Предлагаю такой вариант блокировки: при трех неудачных попытках ввода пароля IP блокируется на 15 минут, если такая блокировка на 15 минут происходит 3 раза, то IP блокируется на 24 часа.

Для реализации блокировки понадобится модель, в которой будет находится 4 поля:

  • IP адрес;
  • Количество попыток ввода пароля;
  • Время разблокировки;
  • Статус блокировки - True - если заблокирован, False - если не заблокирован.

Сразу покажу результат работы блокировок в админке сайта, за пару месяцев уже накопилась небольшая коллекция.


models.py

А теперь посмотрим, как будет выглядеть модель для временных блокировок от подбора пароля, а также, как настроить админку, чтобы таблица с блокировками выглядела так, как показано на рисунке выше.

  1. from django.db import models
  2. from django.contrib import admin
  3.  
  4.  
  5. class TemporaryBanIp(models.Model):
  6. class Meta:
  7. db_table = "TemporaryBanIp"
  8.  
  9. ip_address = models.GenericIPAddressField("IP адрес")
  10. attempts = models.IntegerField("Неудачных попыток", default=0)
  11. time_unblock = models.DateTimeField("Время разблокировки", blank=True)
  12. status = models.BooleanField("Статус блокировки", default=False)
  13.  
  14. def __str__(self):
  15. return self.ip_address
  16.  
  17.  
  18. class TemporaryBanIpAdmin(admin.ModelAdmin):
  19. list_display = ('ip_address', 'status', 'attempts', 'time_unblock')
  20. search_fields = ('ip_address',)

admin.py

Регистрация модели в админке

  1. from django.contrib import admin
  2. from .models import TemporaryBanIp, TemporaryBanIpAdmin
  3.  
  4.  
  5. admin.site.register(TemporaryBanIp, TemporaryBanIpAdmin)

views.py

Модифицируем метод post кастомизированной страницы авторизации из прошлой статьи. В данном коде также используется специальная функция для получения IP адреса из запроса .

  1. class ELoginView(View):
  2.  
  3. # код метода get
  4.  
  5. def post(self, request):
  6. # забираем данные формы авторизации из запроса
  7. form = AuthenticationForm(request, data=request.POST)
  8.  
  9. # забираем IP адрес из запроса
  10. ip = get_client_ip(request)
  11. # получаем или создаём новую запись об IP, с которого вводится пароль, на предмет блокировки
  12. obj, created = TemporaryBanIp.objects.get_or_create(
  13. defaults={
  14. 'ip_address': ip,
  15. 'time_unblock': timezone.now()
  16. },
  17. ip_address=ip
  18. )
  19.  
  20. # если IP заблокирован и время разблокировки не настало
  21. if obj.status is True and obj.time_unblock > timezone.now():
  22. context = create_context_username_csrf(request)
  23. if obj.attempts == 3 or obj.attempts == 6:
  24. # то открываем страницу с сообщением о блокировки на 15 минут при 3 и 6 неудачных попытках входа
  25. return render_to_response('accounts/block_15_minutes.html', context=context)
  26. elif obj.attempts == 9:
  27. # или открываем страницу о блокировке на 24 часа, при 9 неудачных попытках входа
  28. return render_to_response('accounts/block_24_hours.html', context=context)
  29. elif obj.status is True and obj.time_unblock < timezone.now():
  30. # если IP заблокирован, но время разблокировки настало, то разблокируем IP
  31. obj.status = False
  32. obj.save()
  33.  
  34. # если пользователь ввёл верные данные, то авторизуем его и удаляем запись о блокировке IP
  35. if form.is_valid():
  36. auth.login(request, form.get_user())
  37. obj.delete()
  38.  
  39. next = urlparse(get_next_url(request)).path
  40. if next == '/admin/login/' and request.user.is_staff:
  41. return redirect('/admin/')
  42. return redirect(next)
  43. else:
  44. # иначе считаем попытки и устанавливаем время разблокировки и статус блокировки
  45. obj.attempts += 1
  46. if obj.attempts == 3 or obj.attempts == 6:
  47. obj.time_unblock = timezone.now() + timezone.timedelta(minutes=15)
  48. obj.status = True
  49. elif obj.attempts == 9:
  50. obj.time_unblock = timezone.now() + timezone.timedelta(1)
  51. obj.status = True
  52. elif obj.attempts > 9:
  53. obj.attempts = 1
  54. obj.save()
  55.  
  56. context = create_context_username_csrf(request)
  57. context['login_form'] = form
  58.  
  59. return render_to_response('accounts/login.html', context=context)

Таким вот способом можно сделать довольно простое противодействие брутфорсу пароля для небольшого сайта на Django.

Для Django рекомендую VDS-сервера хостера Timeweb .

Вам это нравится? Поделитесь в социальных сетях!

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь