Проверка CSRF не удалась. Запрос прерван. Проверка происхождения не удалась

Вот моя установка:

localhost (Windows 11)
  - Nginx
      listening on port 80 and 443, 80 is NOT automatically redirected to 443
      each proxy_passed to http://wsgi-server where wsgi-server=127.0.0.1:8080
  - waitress_wsgi running as a service on port 8080

Вот конфигурация Django:

<!-- email_test.html -->
<!-- ... -->
<form action="{% url 'identity:email_test' %}" method="post">
  {% csrf_token %}
  {{ email_form }}
  {% translate 'Send email' as submit_translated %}
  <!-- I use django_bootstrap5 -->
  {% bootstrap_button button_type="submit" content=submit_translated extra_classes='w-100'%}
</form>
# settings.py ----------
MIDDLEWARE = {
  # ...
  'django.middleware.csrf.CsrfViewMiddleware',
  # ...
}

# forms.py -------------
class EmailTestForm(forms.Form):
  email = forms.EmailField(
    # help_text=password_validation.password_validators_help_text_html(),
    label=_('Email'),
    max_length=128,
  )

# views.py -------------
def email_test(request):
  context = {}
  context.update(template_globals())
  if request.method == "POST":
    email_form = EmailTestForm(request.POST)
    if email_form.is_valid():
      email_obj = EmailMessage(subject='Hello', body='Email body',
                               from_email='noreply@nutrihub.hnet',
                               to=[email_form.cleaned_data.get('email')])
      email_obj.send(fail_silently=False)
  else:
    email_form = EmailTestForm()

  context['email_form'] = email_form
  return render(request, "identity/email_test.html", context)

Вот мои тестовые результаты при посещении URL в браузере:

  1. py manage.py runserver (порт по умолчанию 8000), браузер http://127.0.0.1:8000, пустой settings.CSRF_TRUSTED_ORIGINS: Работает нормально.
  2. Браузер http://localhost или http://127.0.0.1 или https://localhost или https://127.0.0.1 с отдельной записью не в settings.CSRF_TRUSTED_ORIGINS: CSRF-ошибка.
  3. Браузер http://localhost или http://127.0.0.1 или https://localhost или https://127.0.0.1 с отдельной записью не settings.CSRF_TRUSTED_ORIGINS: Работает нормально.
  4. Браузер https://mymachine.net с этой записью в etc/hosts разрешается в 127.0.0.1, а в settings.CSRF_TRUSTED_ORIGINS нет: CSRF error.
  5. Браузер https://mymachine.net с этой записью в etc/hosts, разрешающейся в 127.0.0.1 и в settings.CSRF_TRUSTED_ORIGINS: Работает нормально.
  6. Браузер http://localhost:8080 или http://localhost или http://mymachine.net:8080: Работает нормально.

Значит ли это, что для (2-5), поскольку фактическим сервером, на котором работает приложение Django, является WSGI-сервер на порту 8080, запрос, переданный с веб-сервера, не считается тем же сайтом?

Мне удалось решить эту проблему. Благодаря этому решению мне не пришлось добавлять никаких записей в settings.CSRF_TRUSTED_ORIGINS.

  1. Nginx config:
  upstream wsgi-server {
    server 127.0.0.1:8080;
  }
  server {
    # ...
    location / {
      proxy_pass http://wsgi-server/;
      # These resolved CSRF error
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-Forwarded-Host $host;
      proxy_set_header X-Forwarded-Port $server_port;
    }
  }
  1. Конфигурация WSGI Waitress (чтобы X-Forwarded-* проходил в Django):
# waitress_wsgi.py
  serve(application,
        trusted_proxy='proxy-ip',
        trusted_proxy_headers=('x-forwarded-host', 'x-forwarded-proto',
                               'x-forwarded-port'))

После этого http|https, localhost|127.0.0.1|mymachine.net, anyport, начали работать без ошибок.

Вернуться на верх