0

I have an application that is fronted by a Varnish server. Parts of the page is rendered using ESI includes.

My problem is that the upstream response includes an encrypted session cookie, which among other things contains a CSRF token (no server-side session storage at all).

For an initial request (no cookie in the request), the ESI requests will not include a cookie set by the first response from the upstream server.

I've tried setting req.http.Cookie in the vcl_deliver hook, as it's the only place in the request flow I've found where both req and res are R/W accessible. However, looking at the requests with varnishlog reveals the ESI requests are unaffected and don't include the cookie.

I've done my best to trawl through the documentation, but can't find anything remotely useful.

Is it possible to achieve what I want, i.e. update req so that the ESI requests include the cookie returned by the initial upstream response?

1 Answer 1

1

We need to make a clear distinction between a request containing a Cookie header and a response containing a Set-Cookie header.

Assuming a CSRF token was set through a Set-Cookie header of the parent response, you probably want to access that value through a Cookie request header in your ESI subrequest.

Assuming the Cookie header already contains the CSRF token

The req_top.http.Cookie variable has access to the cookies of the parent request, however req_top not accessible in vcl_backend_response where the ESI placeholders are parsed.

You can bypass this limitation with the following VCL snippet:

sub vcl_recv {
    if (req.esi_level > 0 ) {
        set req.http.X-Parent-Cookie = req_top.http.Cookie;
    }
}

This will enable the X-Parent-Cookie header which is available in vcl_backend_response through bereq.http.X-Parent-Cookie.

Assuming the Cookie header does not yet contain the CSRF token

It is realistic to assume that req_top.http.Cookie doesn't yet contain the value of the CSRF token because when ESI subrequests are processed, the Cookie header is not yet set by the client.

The only solution I can think off is storing the parent Set-Cookie value in a variable. Variables aren't supported natively in Varnish and require the official https://github.com/varnish/varnish-modules to be installed.

You'll have to compile this from source.

See https://github.com/varnish/varnish-modules/blob/master/src/vmod_var.vcc for the vmod_var API and code examples.

2
  • THANK YOU! I completely forgot about req_top.
    – nikc.org
    Mar 18, 2022 at 10:55
  • To elaborate a bit, I amend req in vcl_deliver, setting req.http.X-Updated-Cookie when req.do_esi == true. Then in vcl_recv, when req.esi_level > 0, if req_top.http.X-Update-Cookie is set I copy it into req.http.Cookie. Works a treat. Thankfully global vars not required.
    – nikc.org
    Mar 18, 2022 at 16:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .