在 Varnish 缓存的视图上使用 Django 的 CSRF 保护
我有一个带有使用 CSRF 保护的表单的 Django 视图。我希望当有正常的 GET 请求时,Varnish 缓存这个视图(因为所有用户都需要相同的表单,无需登录)。
所以有两个挑战:
如何在 Varnish 中缓存此页面,而不向用户提供 csrf 隐藏字段的缓存/旧版本?是否可以缓存带有 CSRF 字段的页面?
默认情况下,我的 Varnish 会删除所有 cookie,我怎样才能轻松地让它删除除 csrftoken cookie 之外的所有 cookie?我是否必须设置特定的 CSRF_COOKIE_DOMAIN?
I have a Django view with a form that uses CSRF protection. I want this view to be cached by Varnish when there is a normal GET request (since all users need the same form, no login).
So there are two challenges:
How to cache this page in Varnish and not delivered cached/old versions of the csrf hidden field to the user? Is it at all possible to cache pages with CSRF field?
My Varnish by default strips out all cookies, how could I easily make it strip all cookies, except the csrftoken cookie? And do I have to set a specific CSRF_COOKIE_DOMAIN?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这已经晚了几年了,但这是我最近解决这个问题的方法。
诀窍是使用 varnish 支持的 ESI。我们获取 CSRF 片段并将其粘贴到自己的页面中,在使用 varnish 时通过 ESI 包含它,否则直接包含它(例如运行本地开发服务器时)。
csrf_esi.html:
csrf_token.html
urls.py
csrf_esi.py
settings.py
Varnish config
您还需要将
csrf_esi.html
页面列入白名单,以便它永远不会被缓存,并添加set beresp.do_esi = true;
在vcl_fetch
函数内。我会对此进行更多详细说明,但我没有设置系统的这一部分,而且我自己也不是 100% 清楚。现在,您可以像使用普通
{% csrf_token %}
标记一样简单地使用它:设置起来相当麻烦,但一旦完成,您就不必再查看它了。
This is a couple of years late, but here's how I got around this problem recently.
The trick is to use ESI, which varnish supports. We take the CSRF snippet and stick it into its own page, including it via ESI when going through varnish, and directly otherwise (such as when running the local dev server).
csrf_esi.html:
csrf_token.html
urls.py
csrf_esi.py
settings.py
Varnish config
You also need to whitelist the
csrf_esi.html
page so it never gets cached and addset beresp.do_esi = true;
inside thevcl_fetch
function. I'd elaborate more on this, but I didn't set this part of the system up and am not 100% clear myself.Now you can simply use it like you do the normal
{% csrf_token %}
tag:It's quite a bit to set up, but once you do, you'll never have to look at it again.
在视图上使用 CSRF 本质上意味着视图的每个渲染本质上都是不同的(即使只有一个隐藏字段的值发生变化)。在这种情况下缓存不起作用。
然而,正如您似乎已经猜到的那样,Django 确实提供了绕过此限制的机制,即 cookies。因此,在第二部分中,需要完成两件事:
如果请求来自与处理它的域不同的域,则只需在 Django 中设置
CSRF_COOKIE_DOMAIN
。Using CSRF on a view essentially means that each render of the view is inherently different (even though only the value of one hidden field is changing). Caching doesn't work in such a scenario.
However, Django does provide mechanisms for getting around this limitation, namely cookies, as you seem to already have guessed. So on your second part, there's two things that need to be done:
You only need to set
CSRF_COOKIE_DOMAIN
in Django if the request will be coming from a different domain than where it is processed.我在使用 @csrf_protect 和 AJX 时遇到了类似的问题,如果有人使用这个装饰器,这可能会有所帮助
以及向 Varnish 添加例外。确保带有表单的视图和正在发布数据的视图都使用装饰器。
我只在帖子视图上有@csrf_protect,它在本地测试工作正常,但是当我上线时,出现了 403 验证失败的问题,将装饰器添加到页面视图修复了此问题
I had similar issues using @csrf_protect and AJX, if anyone is using this decorator this might help
As well as adding exceptions to Varnish. Make sure that both the view with the form and the view that the data is being posted to use the decorator.
I only had @csrf_protect on the post view which worked fine testing locally but when i went live o got a 403 verification failed issue adding the decorator tot he page view fixed this