• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

.circleci/H18-Sep-2019-

.github/H18-Sep-2019-

AUTHORSH A D18-Sep-2019749

Gopkg.lockH A D18-Sep-2019726

Gopkg.tomlH A D18-Sep-2019757

LICENSEH A D18-Sep-20191.5 KiB

README.mdH A D18-Sep-201911.3 KiB

context.goH A D18-Sep-2019539

csrf.goH A D18-Sep-20198.6 KiB

csrf_test.goH A D18-Sep-201910 KiB

doc.goH A D18-Sep-20195.9 KiB

go.modH A D18-Sep-2019124

go.sumH A D18-Sep-2019342

helpers.goH A D18-Sep-20196.1 KiB

helpers_test.goH A D18-Sep-20197.5 KiB

options.goH A D18-Sep-20195 KiB

options_test.goH A D18-Sep-20192.4 KiB

store.goH A D18-Sep-20192.1 KiB

store_test.goH A D18-Sep-20193 KiB

README.md

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