1# gorilla/csrf 2 3[![GoDoc](https://godoc.org/github.com/gorilla/csrf?status.svg)](https://godoc.org/github.com/gorilla/csrf) 4[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/csrf/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/csrf?badge) 5[![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com) 6[![CircleCI](https://circleci.com/gh/gorilla/csrf.svg?style=svg)](https://circleci.com/gh/gorilla/csrf) 7 8gorilla/csrf is a HTTP middleware library that provides [cross-site request 9forgery](http://blog.codinghorror.com/preventing-csrf-and-xsrf-attacks/) (CSRF) 10protection. It includes: 11 12- The `csrf.Protect` middleware/handler provides CSRF protection on routes 13 attached to a router or a sub-router. 14- A `csrf.Token` function that provides the token to pass into your response, 15 whether that be a HTML form or a JSON response body. 16- ... and a `csrf.TemplateField` helper that you can pass into your `html/template` 17 templates to replace a `{{ .csrfField }}` template tag with a hidden input 18 field. 19 20gorilla/csrf is designed to work with any Go web framework, including: 21 22- The [Gorilla](https://www.gorillatoolkit.org/) toolkit 23- Go's built-in [net/http](http://golang.org/pkg/net/http/) package 24- [Goji](https://goji.io) - see the [tailored fork](https://github.com/goji/csrf) 25- [Gin](https://github.com/gin-gonic/gin) 26- [Echo](https://github.com/labstack/echo) 27- ... and any other router/framework that rallies around Go's `http.Handler` interface. 28 29gorilla/csrf is also compatible with middleware 'helper' libraries like 30[Alice](https://github.com/justinas/alice) and [Negroni](https://github.com/codegangsta/negroni). 31 32## Install 33 34With a properly configured Go toolchain: 35 36```sh 37go get github.com/gorilla/csrf 38``` 39 40## Examples 41 42- [HTML Forms](#html-forms) 43- [JavaScript Apps](#javascript-applications) 44- [Google App Engine](#google-app-engine) 45- [Setting SameSite](#setting-samesite) 46- [Setting Options](#setting-options) 47 48gorilla/csrf is easy to use: add the middleware to your router with 49the below: 50 51```go 52CSRF := csrf.Protect([]byte("32-byte-long-auth-key")) 53http.ListenAndServe(":8000", CSRF(r)) 54``` 55 56...and then collect the token with `csrf.Token(r)` in your handlers before 57passing it to the template, JSON body or HTTP header (see below). 58 59Note that the authentication key passed to `csrf.Protect([]byte(key))` should be 6032-bytes long and persist across application restarts. Generating a random key 61won't allow you to authenticate existing cookies and will break your CSRF 62validation. 63 64gorilla/csrf inspects the HTTP headers (first) and form body (second) on 65subsequent POST/PUT/PATCH/DELETE/etc. requests for the token. 66 67### HTML Forms 68 69Here's the common use-case: HTML forms you want to provide CSRF protection for, 70in order to protect malicious POST requests being made: 71 72```go 73package main 74 75import ( 76 "net/http" 77 78 "github.com/gorilla/csrf" 79 "github.com/gorilla/mux" 80) 81 82func main() { 83 r := mux.NewRouter() 84 r.HandleFunc("/signup", ShowSignupForm) 85 // All POST requests without a valid token will return HTTP 403 Forbidden. 86 // We should also ensure that our mutating (non-idempotent) handler only 87 // matches on POST requests. We can check that here, at the router level, or 88 // within the handler itself via r.Method. 89 r.HandleFunc("/signup/post", SubmitSignupForm).Methods("POST") 90 91 // Add the middleware to your router by wrapping it. 92 http.ListenAndServe(":8000", 93 csrf.Protect([]byte("32-byte-long-auth-key"))(r)) 94 // PS: Don't forget to pass csrf.Secure(false) if you're developing locally 95 // over plain HTTP (just don't leave it on in production). 96} 97 98func ShowSignupForm(w http.ResponseWriter, r *http.Request) { 99 // signup_form.tmpl just needs a {{ .csrfField }} template tag for 100 // csrf.TemplateField to inject the CSRF token into. Easy! 101 t.ExecuteTemplate(w, "signup_form.tmpl", map[string]interface{}{ 102 csrf.TemplateTag: csrf.TemplateField(r), 103 }) 104 // We could also retrieve the token directly from csrf.Token(r) and 105 // set it in the request header - w.Header.Set("X-CSRF-Token", token) 106 // This is useful if you're sending JSON to clients or a front-end JavaScript 107 // framework. 108} 109 110func SubmitSignupForm(w http.ResponseWriter, r *http.Request) { 111 // We can trust that requests making it this far have satisfied 112 // our CSRF protection requirements. 113} 114``` 115 116Note that the CSRF middleware will (by necessity) consume the request body if the 117token is passed via POST form values. If you need to consume this in your 118handler, insert your own middleware earlier in the chain to capture the request 119body. 120 121### JavaScript Applications 122 123This approach is useful if you're using a front-end JavaScript framework like 124React, Ember or Angular, and are providing a JSON API. Specifically, we need 125to provide a way for our front-end fetch/AJAX calls to pass the token on each 126fetch (AJAX/XMLHttpRequest) request. We achieve this by: 127 128- Parsing the token from the `<input>` field generated by the 129 `csrf.TemplateField(r)` helper, or passing it back in a response header. 130- Sending this token back on every request 131- Ensuring our cookie is attached to the request so that the form/header 132 value can be compared to the cookie value. 133 134We'll also look at applying selective CSRF protection using 135[gorilla/mux's](https://www.gorillatoolkit.org/pkg/mux) sub-routers, 136as we don't handle any POST/PUT/DELETE requests with our top-level router. 137 138```go 139package main 140 141import ( 142 "github.com/gorilla/csrf" 143 "github.com/gorilla/mux" 144) 145 146func main() { 147 r := mux.NewRouter() 148 csrfMiddleware := csrf.Protect([]byte("32-byte-long-auth-key")) 149 150 api := r.PathPrefix("/api").Subrouter() 151 api.Use(csrfMiddleware) 152 api.HandleFunc("/user/{id}", GetUser).Methods("GET") 153 154 http.ListenAndServe(":8000", r) 155} 156 157func GetUser(w http.ResponseWriter, r *http.Request) { 158 // Authenticate the request, get the id from the route params, 159 // and fetch the user from the DB, etc. 160 161 // Get the token and pass it in the CSRF header. Our JSON-speaking client 162 // or JavaScript framework can now read the header and return the token in 163 // in its own "X-CSRF-Token" request header on the subsequent POST. 164 w.Header().Set("X-CSRF-Token", csrf.Token(r)) 165 b, err := json.Marshal(user) 166 if err != nil { 167 http.Error(w, err.Error(), 500) 168 return 169 } 170 171 w.Write(b) 172} 173``` 174 175In our JavaScript application, we should read the token from the response 176headers and pass it in a request header for all requests. Here's what that 177looks like when using [Axios](https://github.com/axios/axios), a popular 178JavaScript HTTP client library: 179 180```js 181// You can alternatively parse the response header for the X-CSRF-Token, and 182// store that instead, if you followed the steps above to write the token to a 183// response header. 184let csrfToken = document.getElementsByName("gorilla.csrf.Token")[0].value 185 186// via https://github.com/axios/axios#creating-an-instance 187const instance = axios.create({ 188 baseURL: "https://example.com/api/", 189 timeout: 1000, 190 headers: { "X-CSRF-Token": csrfToken } 191}) 192 193// Now, any HTTP request you make will include the csrfToken from the page, 194// provided you update the csrfToken variable for each render. 195try { 196 let resp = await instance.post(endpoint, formData) 197 // Do something with resp 198} catch (err) { 199 // Handle the exception 200} 201``` 202 203If you plan to host your JavaScript application on another domain, you can use the Trusted Origins 204feature to allow the host of your JavaScript application to make requests to your Go application. Observe the example below: 205 206 207```go 208package main 209 210import ( 211 "github.com/gorilla/csrf" 212 "github.com/gorilla/mux" 213) 214 215func main() { 216 r := mux.NewRouter() 217 csrfMiddleware := csrf.Protect([]byte("32-byte-long-auth-key"), csrf.TrustedOrigin([]string{"ui.domain.com"})) 218 219 api := r.PathPrefix("/api").Subrouter() 220 api.Use(csrfMiddleware) 221 api.HandleFunc("/user/{id}", GetUser).Methods("GET") 222 223 http.ListenAndServe(":8000", r) 224} 225 226func GetUser(w http.ResponseWriter, r *http.Request) { 227 // Authenticate the request, get the id from the route params, 228 // and fetch the user from the DB, etc. 229 230 // Get the token and pass it in the CSRF header. Our JSON-speaking client 231 // or JavaScript framework can now read the header and return the token in 232 // in its own "X-CSRF-Token" request header on the subsequent POST. 233 w.Header().Set("X-CSRF-Token", csrf.Token(r)) 234 b, err := json.Marshal(user) 235 if err != nil { 236 http.Error(w, err.Error(), 500) 237 return 238 } 239 240 w.Write(b) 241} 242``` 243 244On the example above, you're authorizing requests from `ui.domain.com` to make valid CSRF requests to your application, so you can have your API server on another domain without problems. 245 246### Google App Engine 247 248If you're using [Google App 249Engine](https://cloud.google.com/appengine/docs/go/how-requests-are-handled#Go_Requests_and_HTTP), 250(first-generation) which doesn't allow you to hook into the default `http.ServeMux` directly, 251you can still use gorilla/csrf (and gorilla/mux): 252 253```go 254package app 255 256// Remember: appengine has its own package main 257func init() { 258 r := mux.NewRouter() 259 r.HandleFunc("/", IndexHandler) 260 // ... 261 262 // We pass our CSRF-protected router to the DefaultServeMux 263 http.Handle("/", csrf.Protect([]byte(your-key))(r)) 264} 265``` 266 267Note: You can ignore this if you're using the 268[second-generation](https://cloud.google.com/appengine/docs/go/) Go runtime 269on App Engine (Go 1.11 and above). 270 271### Setting SameSite 272 273Go 1.11 introduced the option to set the SameSite attribute in cookies. This is 274valuable if a developer wants to instruct a browser to not include cookies during 275a cross site request. SameSiteStrictMode prevents all cross site requests from including 276the cookie. SameSiteLaxMode prevents CSRF prone requests (POST) from including the cookie 277but allows the cookie to be included in GET requests to support external linking. 278 279```go 280func main() { 281 CSRF := csrf.Protect( 282 []byte("a-32-byte-long-key-goes-here"), 283 // instruct the browser to never send cookies during cross site requests 284 csrf.SameSite(csrf.SameSiteStrictMode), 285 ) 286 287 r := mux.NewRouter() 288 r.HandleFunc("/signup", GetSignupForm) 289 r.HandleFunc("/signup/post", PostSignupForm) 290 291 http.ListenAndServe(":8000", CSRF(r)) 292} 293``` 294 295### Setting Options 296 297What about providing your own error handler and changing the HTTP header the 298package inspects on requests? (i.e. an existing API you're porting to Go). Well, 299gorilla/csrf provides options for changing these as you see fit: 300 301```go 302func main() { 303 CSRF := csrf.Protect( 304 []byte("a-32-byte-long-key-goes-here"), 305 csrf.RequestHeader("Authenticity-Token"), 306 csrf.FieldName("authenticity_token"), 307 csrf.ErrorHandler(http.HandlerFunc(serverError(403))), 308 ) 309 310 r := mux.NewRouter() 311 r.HandleFunc("/signup", GetSignupForm) 312 r.HandleFunc("/signup/post", PostSignupForm) 313 314 http.ListenAndServe(":8000", CSRF(r)) 315} 316``` 317 318Not too bad, right? 319 320If there's something you're confused about or a feature you would like to see 321added, open an issue. 322 323## Design Notes 324 325Getting CSRF protection right is important, so here's some background: 326 327- This library generates unique-per-request (masked) tokens as a mitigation 328 against the [BREACH attack](http://breachattack.com/). 329- The 'base' (unmasked) token is stored in the session, which means that 330 multiple browser tabs won't cause a user problems as their per-request token 331 is compared with the base token. 332- Operates on a "whitelist only" approach where safe (non-mutating) HTTP methods 333 (GET, HEAD, OPTIONS, TRACE) are the _only_ methods where token validation is not 334 enforced. 335- The design is based on the battle-tested 336 [Django](https://docs.djangoproject.com/en/1.8/ref/csrf/) and [Ruby on 337 Rails](http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html) 338 approaches. 339- Cookies are authenticated and based on the [securecookie](https://github.com/gorilla/securecookie) 340 library. They're also Secure (issued over HTTPS only) and are HttpOnly 341 by default, because sane defaults are important. 342- Cookie SameSite attribute (prevents cookies from being sent by a browser 343 during cross site requests) are not set by default to maintain backwards compatibility 344 for legacy systems. The SameSite attribute can be set with the SameSite option. 345- Go's `crypto/rand` library is used to generate the 32 byte (256 bit) tokens 346 and the one-time-pad used for masking them. 347 348This library does not seek to be adventurous. 349 350## License 351 352BSD licensed. See the LICENSE file for details. 353