gorilla/csrf explained

Theodoros Ntakouris
Artisans of Tech
Published in
3 min readAug 5, 2017

Why ?
I saw a guy who posted the same question 2 days in a row, on the Gophers Slack #golang-newbies channel and decided to jump in and help!

Overview
gorilla/csrf does quite a lot of stuff to protect your application from csrf attacks, but the whole source is about 5 go source files (and 5 test ones), so it wasn’t that hard to dive into the source code and inspect the project further.

Official docs present us with 2 use cases: Serverside HTML Render and JavaScript Frontend.

Serverside HTML Render
In this case, just embed the provided csrf token into the form as a hidden field. That token is then sent back to the server where validation takes place. This is something that is done automatically. Here is the corresponding code snippet:

JavaScript Frontend
This is a bit different case. You can’t inject the token into the form as a hidden field, but you can render it as a meta tag, which you can then retrieve with js and send back it’s contents as a request header.

Sometimes you just can’t serve the fronted from your backend code. Thus, you are not able to render anything on the html via templates. A different approach would be to send a X-CSRF-Token header from the server to the client, which is then going to be passed back as the same header, on the subsequent post!

Remember :
> This library generates unique-per-request (masked) tokens as a mitigation against the BREACH attack.

* You shouldn’t really care about BREACH if you use https and also send HSTS headers (which, ehm, you should — even with self-signed certs).

How does this server-side validation take place?

While exchanging requests with the server, every time a secure session cookie (specifically gorilla/securecookie) gets sent through the wire. This cookie is of course, encrypted and only the server can decrypt. This piece of data contains the masked csrf token that can be unmasked from the client. It is easily possible to override this and just have a regular session cookie without embedded information, while storing the tokens on some key/value store (redis perhaps?) on the server side. To do that, you’d have to fork gorilla/csrf and provide a kv store-backed implementation of the following interface at store.go:

… but that’s something out of scope for this blog post …

Digging deeper
All the actual middleware work is done at csrf.go, lines 126 ~ end.

I will now proceed to outlining what happens upon each request:

First of all, if any request encounters any error while going through this middleware, an error handler is engaged. By default, 403 Forbidden is returned. You can change this and many other things if you provide these so-called options :

The Protect function:

usually receives a mux.Router as a parameter. It sets up defaults and/or overrides them if options are passed. It also sets up the secure cookie instance:

…which we are probably going to discuss in a different post.

Now, upon each request, an attempt is being made to extract the token from the session cookie. If the token is absent (or the cookie is), a new one will be generated, but the current request is going to return 403 Forbidden. Supposing the operation was completed successfully, this extracted token is the real csrf token. The next step would be to check the headers for the X-CSRF-Token. That token is masked by XORing a one-time-pad and the base csrf toke. It should be unmasked and then compared to our previously extracted csrf token. (← That one time pad protects from Breach as well, because in order for someone to perform a breach attack, he would need to send quite a lot of requests)

There’s other magic going on towards the bottom of the function:

Especially, this contextClear on the end is why not a lot of new variables are declared. I believe this is a micro-optimization in order to avoid extra memory allocations; this middleware is supposed to run upon each request… it is a requirement to be efficient!

Lastly, this middleware consumes the request body in order to defend against the attack. You need to store it in the request context with another layer of middleware if you intend to use it in your own handler. You can still read the form data in the following handlers.

Hopefully you now understand a bigger fraction of the what’s-going-on-under-the-hood part of your go web services :) . Don’t forget to give me a ❤ if you like this article, or comment below.

--

--