Skip to content

Commit 21dad7a

Browse files
committed
gorilla/csrf release candidate.
1 parent e694f3f commit 21dad7a

11 files changed

Lines changed: 1507 additions & 0 deletions

File tree

.travis.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
language: go
2+
3+
go:
4+
- 1.4
5+
- tip

README.md

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
# gorilla/csrf
2+
[![GoDoc](https://godoc.org/github.com/gorilla/csrf?status.svg)](https://godoc.org/github.com/gorilla/csrf) [![Build Status](https://travis-ci.org/gorilla/csrf.svg?branch=master)](https://travis-ci.org/gorilla/csrf)
3+
4+
gorilla/csrf is a HTTP middleware library that provides [cross-site request
5+
forgery](http://blog.codinghorror.com/preventing-csrf-and-xsrf-attacks/) (CSRF)
6+
protection. It includes:
7+
8+
* The `csrf.Protect` middleware/handler provides CSRF protection on routes
9+
attached to a router or a sub-router.
10+
* A `csrf.Token` function that provides the token to pass into your response,
11+
whether that be a HTML form or a JSON response body.
12+
* ... and a `csrf.TemplateField` helper that you can pass into your `html/template`
13+
templates to replace a `{{ .csrfField }}` template tag with a hidden input
14+
field.
15+
16+
gorilla/csrf is designed to work with any Go web framework, including:
17+
18+
* The [Gorilla](http://www.gorillatoolkit.org/) toolkit
19+
* Go's built-in [net/http](http://golang.org/pkg/net/http/) package
20+
* [Goji](https://goji.io) - see the [tailored fork](https://github.com/goji/csrf)
21+
* [Gin](https://github.com/gin-gonic/gin)
22+
* [Echo](https://github.com/labstack/echo)
23+
* ... and any other router/framework that rallies around Go's `http.Handler` interface.
24+
25+
gorilla/csrf is also compatible with middleware 'helper' libraries like
26+
[Alice](https://github.com/justinas/alice) and [Negroni](https://github.com/codegangsta/negroni).
27+
28+
## Install
29+
30+
With a properly configured Go toolchain:
31+
```sh
32+
go get github.com/gorilla/csrf
33+
```
34+
35+
## Examples
36+
37+
gorilla/csrf is easy to use: add the middleware to individual handlers with
38+
the below:
39+
40+
```go
41+
CSRF := csrf.Protect([]byte("32-byte-long-auth-key"))
42+
http.HandlerFunc("/route", CSRF(YourHandler))
43+
```
44+
45+
... and then collect the token with `csrf.Token(r)` before passing it to the
46+
template, JSON body or HTTP header (you pick!). gorilla/csrf inspects the form body
47+
(first) and HTTP headers (second) on subsequent POST/PUT/PATCH/DELETE/etc. requests
48+
for the token.
49+
50+
### HTML Forms
51+
52+
Here's the common use-case: HTML forms you want to provide CSRF protection for,
53+
in order to protect malicious POST requests being made:
54+
55+
```go
56+
package main
57+
58+
import (
59+
"net/http"
60+
61+
"github.com/gorilla/csrf"
62+
)
63+
64+
func main() {
65+
r := mux.NewRouter()
66+
r.HandleFunc("/signup", ShowSignupForm)
67+
// All POST requests without a valid token will return HTTP 403 Forbidden.
68+
r.HandleFunc("/signup/post", SubmitSignupForm)
69+
70+
// Add the middleware to your router by wrapping it.
71+
http.ListenAndServe(":8000",
72+
csrf.Protect([]byte("32-byte-long-auth-key"))(r))
73+
}
74+
75+
func ShowSignupForm(w http.ResponseWriter, r *http.Request) {
76+
// signup_form.tmpl just needs a {{ .csrfField }} template tag for
77+
// csrf.TemplateField to inject the CSRF token into. Easy!
78+
t.ExecuteTemplate(w, "signup_form.tmpl", map[string]interface{
79+
csrf.TemplateTag: csrf.TemplateField(r),
80+
})
81+
// We could also retrieve the token directly from csrf.Token(r) and
82+
// set it in the request header - w.Header.Set("X-CSRF-Token", token)
83+
// This is useful if your sending JSON to clients or a front-end JavaScript
84+
// framework.
85+
}
86+
87+
func SubmitSignupForm(w http.ResponseWriter, r *http.Request) {
88+
// We can trust that requests making it this far have satisfied
89+
// our CSRF protection requirements.
90+
}
91+
```
92+
93+
### JSON Responses
94+
95+
This approach is useful if you're using a front-end JavaScript framework like
96+
Ember or Angular, or are providing a JSON API.
97+
98+
We'll also look at applying selective CSRF protection using
99+
[gorilla/mux's](http://www.gorillatoolkit.org/pkg/mux) sub-routers,
100+
as we don't handle any POST/PUT/DELETE requests with our top-level router.
101+
102+
```go
103+
package main
104+
105+
import (
106+
"github.com/gorilla/csrf"
107+
"github.com/gorilla/mux"
108+
)
109+
110+
func main() {
111+
r := mux.NewRouter()
112+
113+
api := r.PathPrefix("/api").Subrouter()
114+
api.HandleFunc("/user/:id", GetUser).Methods("GET")
115+
116+
http.ListenAndServe(":8000",
117+
csrf.Protect([]byte("32-byte-long-auth-key"))(r))
118+
}
119+
120+
func GetUser(w http.ResponseWriter, r *http.Request) {
121+
// Authenticate the request, get the id from the route params,
122+
// and fetch the user from the DB, etc.
123+
124+
// Get the token and pass it in the CSRF header. Our JSON-speaking client
125+
// or JavaScript framework can now read the header and return the token in
126+
// in its own "X-CSRF-Token" request header on the subsequent POST.
127+
w.Header().Set("X-CSRF-Token", csrf.Token(r))
128+
b, err := json.Marshal(user)
129+
if err != nil {
130+
http.Error(w, err.Error(), 500)
131+
return
132+
}
133+
134+
w.Write(b)
135+
}
136+
```
137+
138+
### Setting Options
139+
140+
What about providing your own error handler and changing the HTTP header the
141+
package inspects on requests? (i.e. an existing API you're porting to Go). Well,
142+
gorilla/csrf provides options for changing these as you see fit:
143+
144+
```go
145+
func main() {
146+
CSRF := csrf.Protect(
147+
[]byte("a-32-byte-long-key-goes-here"),
148+
csrf.RequestHeader("Authenticity-Token"),
149+
csrf.FieldName("authenticity_token"),
150+
csrf.ErrorHandler(http.HandlerFunc(serverError(403))),
151+
)
152+
153+
r := mux.NewRouter()
154+
r.HandleFunc("/signup", GetSignupForm)
155+
r.HandleFunc("/signup/post", PostSignupForm)
156+
157+
http.ListenAndServe(":8000", CSRF(r))
158+
}
159+
```
160+
161+
Not too bad, right?
162+
163+
If there's something you're confused about or a feature you would like to see
164+
added, open an issue.
165+
166+
## Design Notes
167+
168+
Getting CSRF protection right is important, so here's some background:
169+
170+
* This library generates unique-per-request (masked) tokens as a mitigation
171+
against the [BREACH attack](http://breachattack.com/).
172+
* The 'base' (unmasked) token is stored in the session, which means that
173+
multiple browser tabs won't cause a user problems as their per-request token
174+
is compared with the base token.
175+
* Operates on a "whitelist only" approach where safe (non-mutating) HTTP methods
176+
(GET, HEAD, OPTIONS, TRACE) are the *only* methods where token validation is not
177+
enforced.
178+
* The design is based on the battle-tested
179+
[Django](https://docs.djangoproject.com/en/1.8/ref/csrf/) and [Ruby on
180+
Rails](http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html)
181+
approaches.
182+
* Cookies are authenticated and based on the [securecookie](https://github.com/gorilla/securecookie)
183+
library. They're also Secure (issued over HTTPS only) and are HttpOnly
184+
by default, because sane defaults are important.
185+
* Go's `crypto/rand` library is used to generate the 32 byte (256 bit) tokens
186+
and the one-time-pad used for masking them.
187+
188+
This library does not seek to be adventurous.
189+
190+
## License
191+
192+
BSD licensed. See the LICENSE file for details.

0 commit comments

Comments
 (0)