Реклама

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

TutorialDjangoIP, брутфорс, подбор пароля, блокировка, Django, brute force850

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

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

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

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

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

models.py

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

from django.db import models
from django.contrib import admin


class TemporaryBanIp(models.Model):
    class Meta:
        db_table = "TemporaryBanIp"

    ip_address = models.GenericIPAddressField("IP адрес")
    attempts = models.IntegerField("Неудачных попыток", default=0)
    time_unblock = models.DateTimeField("Время разблокировки", blank=True)
    status = models.BooleanField("Статус блокировки", default=False)

    def __str__(self):
        return self.ip_address


class TemporaryBanIpAdmin(admin.ModelAdmin):
    list_display = ('ip_address', 'status', 'attempts', 'time_unblock')
    search_fields = ('ip_address',)

admin.py

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

from django.contrib import admin
from .models import TemporaryBanIp, TemporaryBanIpAdmin


admin.site.register(TemporaryBanIp, TemporaryBanIpAdmin)

views.py

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

class ELoginView(View):

    # код метода get

    def post(self, request):
        # забираем данные формы авторизации из запроса
        form = AuthenticationForm(request, data=request.POST)

        # забираем IP адрес из запроса
        ip = get_client_ip(request)
        # получаем или создаём новую запись об IP, с которого вводится пароль, на предмет блокировки
        obj, created = TemporaryBanIp.objects.get_or_create(
            defaults={
                'ip_address': ip,
                'time_unblock': timezone.now()
            },
            ip_address=ip
        )

        # если IP заблокирован и время разблокировки не настало
        if obj.status is True and obj.time_unblock > timezone.now():
            context = create_context_username_csrf(request)
            if obj.attempts == 3 or obj.attempts == 6:
                # то открываем страницу с сообщением о блокировки на 15 минут при 3 и 6 неудачных попытках входа
                return render_to_response('accounts/block_15_minutes.html', context=context)
            elif obj.attempts == 9:
                # или открываем страницу о блокировке на 24 часа, при 9 неудачных попытках входа
                return render_to_response('accounts/block_24_hours.html', context=context)
        elif obj.status is True and obj.time_unblock < timezone.now():
            # если IP заблокирован, но время разблокировки настало, то разблокируем IP 
            obj.status = False
            obj.save()

        # если пользователь ввёл верные данные, то авторизуем его и удаляем запись о блокировке IP
        if form.is_valid():
            auth.login(request, form.get_user())
            obj.delete()

            next = urlparse(get_next_url(request)).path
            if next == '/admin/login/' and request.user.is_staff:
                return redirect('/admin/')
            return redirect(next)
        else:
            # иначе считаем попытки и устанавливаем время разблокировки и статус блокировки 
            obj.attempts += 1
            if obj.attempts == 3 or obj.attempts == 6:
                obj.time_unblock = timezone.now() + timezone.timedelta(minutes=15)
                obj.status = True
            elif obj.attempts == 9:
                obj.time_unblock = timezone.now() + timezone.timedelta(1)
                obj.status = True
            elif obj.attempts > 9:
                obj.attempts = 1
            obj.save()

        context = create_context_username_csrf(request)
        context['login_form'] = form

        return render_to_response('accounts/login.html', context=context)

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

@EVILEG 9 января 2017 г. 20:45

Реклама

Реклама

Комментарии

Комментарии

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

Реклама

Реклама