Использование Django CSRF-защиты при просмотре изображений, хранящихся в Varnish

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

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

  • Как кэшировать эту страницу в лаке, а не передавать кэшированные/старые версии скрытого поля csrf пользователю? Возможно ли кэшировать страницы с полем CSRF?

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

Ответ 1

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

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

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

Ответ 2

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

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

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

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

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


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

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

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

Ответ 3

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

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

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