Projet

Général

Profil

0001-add-a-honeypot-middleware-50108.patch

Benjamin Dauvergne, 14 janvier 2021 11:28

Télécharger (5,44 ko)

Voir les différences:

Subject: [PATCH] add a honeypot middleware (#50108)

Forms must be instrumented by adding a 'robotcheck' checkbox input, then
a request.session['is_robot'] boolean signals if the request is possibly from a
spam robot.
 src/authentic2/middleware.py                       | 14 ++++++++++++++
 src/authentic2/settings.py                         |  1 +
 .../login_password_registration_form.html          |  1 +
 .../registration/registration_complete.html        |  6 ++++++
 src/authentic2/views.py                            |  2 ++
 tests/test_registration.py                         | 14 ++++++++++++++
 6 files changed, 38 insertions(+)
src/authentic2/middleware.py
227 227

  
228 228
        return get_response(request)
229 229
    return middleware
230

  
231

  
232
def honeypot_middleware(get_response):
233
    # The following HTML code must be added to forms for the middleware to work :
234
    # <label style="display: none"><input type="checkbox" name="robotcheck" value="robotcheck"><span>{% trans "Robot detection, do not check !" %}</span></label>
235

  
236
    def middleware(request):
237
        if request.POST:
238
            if 'robotcheck' in request.POST:
239
                request.session['is_robot'] = True
240
            elif 'is_robot' in request.session:  # prevent persistance
241
                del request.session['is_robot']
242
        return get_response(request)
243
    return middleware
src/authentic2/settings.py
102 102
    'django.contrib.auth.middleware.AuthenticationMiddleware',
103 103
    'django.contrib.messages.middleware.MessageMiddleware',
104 104
    'authentic2.middleware.journal_middleware',
105
    'authentic2.middleware.honeypot_middleware',
105 106
)
106 107

  
107 108
DATABASES['default']['ATOMIC_REQUESTS'] = True
src/authentic2/templates/authentic2/login_password_registration_form.html
4 4
<form enctype="multipart/form-data" method="post" class="pk-mark-optional-fields">
5 5
  {% csrf_token %}
6 6
  {{ form|with_template }}
7
  <label style="display: none"><input type="checkbox" name="robotcheck" value="robotcheck"><span>{% trans "Robot detection, do not check !" %}</span></label>
7 8
  <button class="submit-button">{% trans 'Submit' %}</button>
8 9
</form>
9 10
{% endblock %}
src/authentic2/templates/registration/registration_complete.html
6 6
{% endblock %}
7 7

  
8 8
{% block content %}
9
  {% if request.session.is_robot %}
10
    {% block robot-detected %}
11
      <p>{% blocktrans %}<b>Your registration request is refused.</b> Indeed your browser checked an hidden anti-robot checkbox on the registration form. A browser extension may produce this behaviour, in this case disable the extension and try agin.{% endblocktrans %}</p>
12
    {% endblock %}
13
  {% else %}
9 14
  {% block instructions %}
10 15
  <p><strong>
11 16
  {% blocktrans with email=request.session.registered_email %}
......
36 41
  {% block back %}
37 42
  <p><a href="{{ next_url }}">{% trans "Back" %}</a></p>
38 43
  {% endblock %}
44
  {% endif %}
39 45
{% endblock %}
src/authentic2/views.py
829 829
        return super(BaseRegistrationView, self).dispatch(request, *args, **kwargs)
830 830

  
831 831
    def form_valid(self, form):
832
        if self.request.session.get('is_robot'):
833
            return utils.redirect(self.request, 'registration_complete', params={REDIRECT_FIELD_NAME: self.next_url})
832 834
        email = form.cleaned_data.pop('email')
833 835

  
834 836
        # if an email has already been sent, warn once before allowing resend
tests/test_registration.py
819 819
    assert user.attributes.preferred_color == 'bleu'
820 820
    assert user.email == 'john.doe2@example.com'
821 821
    assert user.email_verified is True
822

  
823

  
824
def test_honeypot(app, db, settings, mailoutbox):
825
    settings.DEFAULT_FROM_EMAIL = 'show only addr <noreply@example.net>'
826

  
827
    response = app.get(utils.make_url('registration_register'))
828
    response = app.post(utils.make_url('registration_register'), params={
829
        'email': 'testbot@entrouvert.com',
830
        'csrfmiddlewaretoken': response.context['csrf_token'],
831
        'robotcheck': 'a',
832
    })
833
    response = response.follow()
834
    assert len(mailoutbox) == 0
835
    assert 'Your registration request is refused' in response
822
-