Использование CSRF-защиты Django для представлений, кэшированных Varnish. - PullRequest
10 голосов
/ 09 июня 2011

У меня есть представление Django с формой, которая использует защиту CSRF.Я хочу, чтобы это представление кэшировалось Varnish при нормальном запросе GET (поскольку все пользователи нуждаются в одинаковой форме, без входа в систему).

Итак, есть две проблемы:

  1. Как кэшировать эту страницу в Varnish и не доставлять кешированные / старые версии скрытого поля csrf пользователю?Можно ли вообще кэшировать страницы с полем CSRF?

  2. Мой Varnish по умолчанию удаляет все куки, как я могу легко сделать так, чтобы он удалял все куки, кроме куки csrftoken?И нужно ли устанавливать конкретный CSRF_COOKIE_DOMAIN?

Ответы [ 3 ]

8 голосов
/ 09 июня 2011

Использование CSRF в представлении, по сути, означает, что каждый рендер представления по своей сути отличается (даже если изменяется только значение одного скрытого поля).Кэширование не работает в таком сценарии.

Тем не менее, Django предоставляет механизмы для преодоления этого ограничения, а именно куки, как вы, кажется, уже догадались.Итак, что касается второй части, нужно сделать две вещи:

  1. Настройте Django для отправки файлов cookie CSRF вместо использования скрытого поля.(См .: https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#s-caching)
  2. Запретите Varnish игнорировать файлы cookie, отправляемые Django. (См .: http://www.varnish -cache.org / docs / trunk / tutorial / cookies.html )

Вам нужно установить CSRF_COOKIE_DOMAIN в Django, только если запрос будет поступать из домена, отличного от того, где он обрабатывается.

7 голосов
/ 21 марта 2016

Это на пару лет позже, но вот как я недавно обошел эту проблему.

Хитрость заключается в том, чтобы использовать ESI , который поддерживает лак.Мы берем фрагмент кода CSRF и помещаем его на свою страницу, в том числе через ESI при работе с лаком, и напрямую (например, при запуске локального сервера dev).

csrf_esi.html:

{% csrf_token %}

csrf_token.html

{% if request.META.HTTP_X_VARNISH_USE_CACHE %}
<esi:include src="{% url 'esi_csrf_token' %}" />
{% else %}
{% include "csrf_esi.html" %}
{% endif %}

urls.py

from django.conf.urls import url
from django.views.generic import TemplateView

urlpatterns = [
    ...
    url(r'csrf_esi.html', TemplateView.as_view(template_name="csrf_esi.html"), name='esi_csrf_token'),
]

csrf_esi.py

from django import template

register = template.Library()

@register.inclusion_tag('csrf_token.html', takes_context=True)
def csrf_token_esi(context):
    return context

settings.py

TEMPLATES = [
    {
        ...
        'OPTIONS': {
            ...
            'builtins': [
                'path.to.csrf_esi',
            ],
        }
    }
]

Varnish config

set req.http.X-Varnish-Use-Cache = true;

Вам также необходимо внести белый список страницы csrf_esi.html, чтобы она никогда не кэшировалась, и добавить set beresp.do_esi = true; в функцию vcl_fetch.Я бы более подробно остановился на этом, но я не настроил эту часть системы и сам не на 100% очищаюсь.


Теперь вы можете просто использовать ее, как обычно {% csrf_token %} tag:

<form action="">
    {% csrf_token_esi %}
    <button type="submit">Push me</button>
</form>

Это довольно сложно настроить, но как только вы это сделаете, вам больше не придется смотреть на это снова.

1 голос
/ 29 августа 2012

У меня были похожие проблемы с использованием @csrf_protect и AJX, если кто-то использует этот декоратор, это может помочь

, а также добавить исключения в Varnish.Удостоверьтесь, что и представление с формой, и представление о том, что данные публикуются для использования декоратора.

У меня был только @csrf_protect в представлении публикации, которое работало нормально при локальном тестировании, но когда я начал работать, то получилошибка проверки 403 при добавлении декоратора к просмотру страницы это исправлено

...