10

我有一个使用 CSRF 保护的表单的 Django 视图。当有正常的 GET 请求时,我希望 Varnish 缓存此视图(因为所有用户都需要相同的表单,无需登录)。

所以有两个挑战:

  1. 如何在 Varnish 中缓存此页面,而不向用户提供 csrf 隐藏字段的缓存/旧版本?是否可以缓存带有 CSRF 字段的页面?

  2. 默认情况下,我的 Varnish 会删除所有 cookie,我怎样才能轻松地使其删除除 csrftoken cookie 之外的所有 cookie?我是否必须设置特定的 CSRF_COOKIE_DOMAIN?

4

3 回答 3

9

这已经晚了几年,但这是我最近解决这个问题的方法。

诀窍是使用清漆支持的ESI。我们获取 CSRF 片段并将其粘贴到自己的页面中,当通过 varnish 时通过 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 %}

网址.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

设置.py

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

清漆配置

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>

设置起来相当麻烦,但是一旦设置好,您就不必再看它了。

于 2016-03-21T01:29:31.707 回答
8

在视图上使用 CSRF 本质上意味着视图的每个渲染本质上是不同的(即使只有一个隐藏字段的值在变化)。缓存在这种情况下不起作用。

但是,正如您似乎已经猜到的那样,Django 确实提供了绕过此限制的机制,即 cookie。所以在你的第二部分,有两件事需要做:

  1. 设置 Django 以发送 CSRF cookie 而不是使用隐藏字段。(见:https ://docs.djangoproject.com/en/dev/ref/contrib/csrf/#s-caching )
  2. 让 Varnish 忽略 Django 发送的 cookie。(见:http ://www.varnish-cache.org/docs/trunk/tutorial/cookies.html )

CSRF_COOKIE_DOMAIN如果请求来自与处理它的域不同的域,则只需要在 Django 中进行设置。

于 2011-06-09T14:29:23.117 回答
1

我在使用 @csrf_protect 和 AJX 时遇到了类似的问题,如果有人在使用这个装饰器,这可能会有所帮助

以及向 Varnish 添加例外。确保带有表单的视图和发布数据的视图都使用装饰器。

我在帖子视图上只有@csrf_protect ,它在本地工作得很好,但是当我上线时遇到一个 403 验证失败的问题,将装饰器添加到他的页面视图中解决了这个问题

于 2012-08-29T09:56:24.367 回答