【发布时间】:2021-06-29 12:47:21
【问题描述】:
我正在使用 Varnish 来缓存 Laravel 页面。
为了给每个人显示不同的 CSRF Tokens,我使用 ESI 将 CSRF 从缓存中排除:
app.blade.php
<html lang="fr">
<head>
<title>@yield('title')</title>
<meta name="description" content="@yield('description')">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, minimum-scale=1, maximum-scale=1, initial-scale=1">
<esi:include src="/esi" />
...
在 /esi 中,我只是使用控制器来显示带有 CSRF 令牌的元标记
csrf-token.blade.php
<meta name="csrf-token" content="{{ csrf_token() }}">
在 ajax 表单中,我获取令牌并将其传递给 POST 请求:
form.js
this.formData._token = document.head.querySelector("[name~=csrf-token][content]").content;
axios.post('url', this.formData);
通过 POST 发送的 _token 被接收,但是当 laravel 尝试验证它时,通过 ESI 生成的与 $session->token() 中的不同。
有人知道如何在 Laravel 中使用 Varnish 正确处理 csrf 吗?
这是我的 Varnish 配置文件,如果有帮助的话 default.vcl
sub vcl_recv {
call devicedetect;
if (req.method != "GET" && req.method != "HEAD") {
return (pass);
}
if (req.esi_level == 0 && req.url ~ "^/esi(.*)?") {
return (synth(403, "Error"));
}
return (hash);
}
sub vcl_hash {
hash_data(req.url);
if (req.http.host) {
hash_data(req.http.host);
} else {
hash_data(server.ip);
}
if (req.http.X-UA-Device) {
hash_data(req.http.X-UA-Device);
}
return (lookup);
}
sub vcl_backend_response {
if (bereq.method != "GET"&&bereq.method != "HEAD") {
set beresp.uncacheable = true;
set beresp.ttl = 0s;
return (deliver);
}
if (beresp.http.X-Reverse-Proxy-TTL) {
set beresp.ttl = std.duration(beresp.http.X-Reverse-Proxy-TTL + "s", 0s);
unset beresp.http.X-Reverse-Proxy-TTL;
return (deliver);
}
set beresp.do_esi = true;
set beresp.grace = 5m;
set beresp.ttl = 5h;
set beresp.http.Cache-Control = "public, s-maxage=18000, maxage=3600";
unset beresp.http.set-cookie;
}
【问题讨论】:
-
你好,实际上没有,因为我只处理带有清漆的 GET 请求,我传递了 POST,因此不会缓存响应(并且每次调用都会更新会话令牌)