Explicitly Approving (Whitelisting) Cookies in Varnish With Libvmod-Cookie

Profile image of Mattias Geniar

Mattias Geniar, December 21, 2014

Follow me on Twitter as @mattiasgeniar

In all my previous Varnish 3.x configs, I’ve always used blacklisting as the way of handling Cookies. You explicitly tell which cookies you want to remove in vcl_recv, all others remain. But just as security measures, whitelisting is always better than blacklisting.

Even if you fully manage your site and all code, you may not have full control over 3rd party (client-side) advertisers that use tracking cookies. And those cookies may, even if you don’t approve of the method, be placed under your domain. So the next request to your site suddenly includes (random) tracking cookies, unique for each visitor, and it destroys the caching in vcl_hash.

Please note this guide is focused on Varnish 3.x. Varnish 4.x will have the Cookie VMOD available by default, no custom compiles required!

Blacklisting / Removing cookies in Varnish

This is the common method of removing cookies in vcl_recv.

set req.http.Cookie = regsuball(req.http.Cookie, "has_js=[^;]+(; )?", "");

And you would repeat that line 1, 10 or 100 times, depending on what cookies you want to remove.

Implementing a whitelist of allowed cookies

In order to use a whitelisting approach, you can use the libvmod-cookie VMOD for Varnish 3.x. It allows more fine-grained control over what cookies are preserved and which ones get removed.

In order to use the VMOD, you need to compile it from source. And to compile the VMOD from source, you also need the Varnish source files somewhere on your system. You can still keep the RPM packages from Varnish installed, but the source is needed to compile the VMOD against it.

Preparing the Varnish source

In this guide, I’ll use Varnish 3.0.6 as the base-version to compile against. Download the source and run make to build the binary files, but no not make install as you want to keep the packages from the upstream Varnish repo intact.

$ cd /usr/local/src
$ wget "https://repo.varnish-cache.org/source/varnish-3.0.6.tar.gz"
$ tar xzvf varnish-3.0.6.tar.gz
$ cd varnish-3.0.6
$ ./configure
$ make

Now you have the Varnish source and a built binary available in /usr/local/src/varnish-3.0.6. We’ll use this to compile the VMOD against.

Next, download and compile the libvmod-cookie module.

$ cd /usr/local/src
$ wget "https://github.com/lkarsten/libvmod-cookie/tarball/3.0"
$ tar xzvf 3.0
$ cd lkarsten-libvmod-cookie-fe38614
$ ./configure VARNISHSRC=/usr/local/src/varnish-3.0.6 VMODDIR=/usr/lib64/varnish/vmods/
$ make && make install

The result is a vmod module installed in /usr/lib64/varnish/vmods/.

$ ls -alh /usr/lib64/varnish/vmods/
-rwxr-xr-x 1 root root  955 Dec 21 21:28 libvmod_cookie.la
-rwxr-xr-x 1 root root  42K Dec 21 21:28 libvmod_cookie.so
-rwxr-xr-x 1 root root  16K Oct 16 16:30 libvmod_std.so

The libvmod_std is the standard library included by Varnish. The libvmod_cookie is the new binary module, and you can include the vmod in your VCL code now.

import cookie;

vcl_recv {

And now that the VMOD module is installed and ready for use, you can use the powerful filter_except() function call to pass a comma-separated list of cookies to allow, all others will be removed.

vcl_recv {
  # Let the module parse the "Cookie:" header from the client

  # Filter all except these cookies from it

  # Set the "Cookie:" header to the parsed/filtered value, removing all unnecessary cookies
  set req.http.cookie = cookie.get_string();

Any other cookie besides cookie1 and cookie2 will be removed from the Cookie: header now.

To debug this and to test what cookies are removed and which ones remain, look at my post about seeing which cookies get stripped in the VCL.

Next up: figuring out how to pass regex’s along. ;-)


A few things to keep in mind;

  1. VMODs are compiled, so it’s better to make packages out of them
  2. Since VMODs are compiled against a specific version, they need to match the Varnish version. (so varnish 3.0.5 from RPM/Yum repos and VMODs compiled with 3.0.6 source can mean troubles)
  3. For automating this at scale, you need the VMODs in your own repository
  4. The filter_except() call accepts strings, not regex’s – to match against regex’s, you would need to loop all values

To be continued!

Want to subscribe to the cron.weekly newsletter?

I write a weekly-ish newsletter on Linux, open source & webdevelopment called cron.weekly.

It features the latest news, guides & tutorials and new open source projects. You can sign up via email below.

No spam. Just some good, practical Linux & open source content.