Answer the question
In order to leave comments, you need to log in
Django. How to protect a form from multiple submissions?
Are there ready-made solutions to protect forms from spam? It is better that the annoying captcha does not appear immediately, but after suspicious actions, for example, a lot of requests from the same ip in a certain period of time, a large number of links in the text, or, if this is a login form, then a large number of attempts to log into one account with different ip addresses.
Answer the question
In order to leave comments, you need to log in
class FloodSafeMixin(object):
def __init__(self, *args, **kwargs):
request = kwargs.pop('request', None)
if request:
self._user = request.user.username if request.user.is_authenticated() else None
self._ip = get_ip(request)
self._period = OrderedDict()
self._period['days'] = kwargs.pop('days', None)
self._period['hours'] = kwargs.pop('hours', None)
self._period['minutes'] = kwargs.pop('minutes', None)
self._period['seconds'] = kwargs.pop('seconds', None)
self._period['milliseconds'] = kwargs.pop('milliseconds', None)
if not any(self._period.values()):
self._period = {'minutes': 1}
else:
self._period = OrderedDict([(k, v) for k, v in self._period.items() if v])
else:
self._ip = None
super(FloodSafeMixin, self).__init__(*args, **kwargs)
def clean(self):
cleaned_data = super(FloodSafeMixin, self).clean()
sender_id = hashlib.md5((self._user if self._user else self._ip).encode('utf-8')).hexdigest()
if sender_id:
class_name = self.__class__.__name__
cache_name = 'last-submit.{0}.{1}'.format(class_name, sender_id)
now = datetime.now()
last_submit = cache.get(cache_name, now - timedelta(days=1))
if (now - last_submit) < timedelta(**self._period):
cache.set(cache_name, now)
period = ' '.join([u'{0} {1}'.format(v, _p('genitive', k)) for k, v in self._period.items()])
raise forms.ValidationError(_('Form submitted less than %(period)s ago'), code='flood',
params={'period': period})
else:
if not self.errors:
cache.set(cache_name, now)
return cleaned_data
class FeedbackForm(FloodSafeMixin, forms.Form):
...
class SomeFormHandlerView(FormView):
def get_form_kwargs(self):
kwargs = super(GenericFormHandlerView, self).get_form_kwargs()
kwargs['request'] = self.request
kwargs['minutes'] = 2
return kwargs
...
In my opinion, it is better to write a custom middleware that will protect you from stupid brute force. Offhand logic:
If you want to make protection on the front - use, for example, reCAPTCHA . Save you from stupid bots.
Pushing all the protection logic into a form is a strange solution, very ugly and cumbersome, plus, not extensible.
In the form - only validation and nothing more. No one will look at the code of the form, while protecting against brute force.
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question