Skip to content

Commit 49832e8

Browse files
committed
csrf protection
1 parent 5da914e commit 49832e8

32 files changed

+2039
-30
lines changed

cmd/web/handlers.go

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"os"
77
"path/filepath"
88
"strconv"
9-
"strings"
109

1110
"snippetbox.org/pkg/forms"
1211
"snippetbox.org/pkg/models"
@@ -105,16 +104,6 @@ func (app *App) VersionInfo(w http.ResponseWriter, r *http.Request) {
105104
http.ServeFile(w, r, verFile)
106105
}
107106

108-
func DisableIndex(next http.Handler) http.Handler {
109-
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
110-
if strings.HasSuffix(r.URL.Path, "/") {
111-
http.Error(w, "Nothing to see here", http.StatusNotFound)
112-
return
113-
}
114-
next.ServeHTTP(w, r)
115-
})
116-
}
117-
118107
func (app *App) SignupUser(w http.ResponseWriter, r *http.Request) {
119108
app.RenderHtml(w, r, "signup.page.html", &HtmlData{
120109
Form: &forms.SignupUser{},

cmd/web/middleware.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ package main
33
import (
44
"log"
55
"net/http"
6+
"strings"
7+
8+
"github.com/justinas/nosurf"
69
)
710

811
func LogRequest(next http.Handler) http.Handler {
@@ -37,3 +40,27 @@ func (app *App) RequireLogin(next http.Handler) http.Handler {
3740
next.ServeHTTP(w, r)
3841
})
3942
}
43+
44+
func NoSurf(next http.Handler) http.Handler {
45+
csrfHandler := nosurf.New(next)
46+
csrfHandler.SetBaseCookie(http.Cookie{
47+
HttpOnly: true,
48+
Path: "/",
49+
Secure: true,
50+
})
51+
return csrfHandler
52+
}
53+
54+
func DisableIndex(next http.Handler) http.Handler {
55+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
56+
if strings.HasSuffix(r.URL.Path, "/") {
57+
http.Error(w, "Nothing to see here", http.StatusNotFound)
58+
return
59+
}
60+
next.ServeHTTP(w, r)
61+
})
62+
}
63+
64+
func StripStatic(next http.Handler) http.Handler {
65+
return http.StripPrefix("/static", next)
66+
}

cmd/web/routes.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,20 @@ import (
1010
func (app *App) Routes() http.Handler {
1111
mux := pat.New()
1212

13-
mux.Get("/", http.HandlerFunc(app.Home))
13+
mux.Get("/", alice.New(NoSurf).Then(http.HandlerFunc(app.Home)))
1414

15-
mux.Get("/snippet/new", alice.New(app.RequireLogin).Then(http.HandlerFunc(app.NewSnippet)))
16-
mux.Post("/snippet/new", alice.New(app.RequireLogin).Then(http.HandlerFunc(app.CreateSnippet)))
17-
mux.Get("/snippet/:id", http.HandlerFunc(app.ShowSnippet))
15+
mux.Get("/snippet/new", alice.New(app.RequireLogin, NoSurf).Then(http.HandlerFunc(app.NewSnippet)))
16+
mux.Post("/snippet/new", alice.New(app.RequireLogin, NoSurf).Then(http.HandlerFunc(app.CreateSnippet)))
17+
mux.Get("/snippet/:id", alice.New(NoSurf).Then(http.HandlerFunc(app.ShowSnippet)))
1818

19-
mux.Get("/user/signup", http.HandlerFunc(app.SignupUser))
20-
mux.Post("/user/signup", http.HandlerFunc(app.CreateUser))
21-
mux.Get("/user/login", http.HandlerFunc(app.LoginUser))
22-
mux.Post("/user/login", http.HandlerFunc(app.VerifyUser))
23-
mux.Post("/user/logout", alice.New(app.RequireLogin).Then(http.HandlerFunc(app.LogoutUser)))
19+
mux.Get("/user/signup", alice.New(NoSurf).Then(http.HandlerFunc(app.SignupUser)))
20+
mux.Post("/user/signup", alice.New(NoSurf).Then(http.HandlerFunc(app.CreateUser)))
21+
mux.Get("/user/login", alice.New(NoSurf).Then(http.HandlerFunc(app.LoginUser)))
22+
mux.Post("/user/login", alice.New(NoSurf).Then(http.HandlerFunc(app.VerifyUser)))
23+
mux.Post("/user/logout", alice.New(app.RequireLogin, NoSurf).Then(http.HandlerFunc(app.LogoutUser)))
2424

2525
fileServer := http.FileServer(http.Dir(app.staticDir))
26-
mux.Get("/static/", http.StripPrefix("/static", DisableIndex(fileServer)))
26+
mux.Get("/static/", alice.New(StripStatic, DisableIndex).Then(fileServer))
2727

2828
mux.Get("/version", http.HandlerFunc(app.VersionInfo))
2929

cmd/web/views.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,18 @@ import (
77
"path/filepath"
88
"time"
99

10+
"github.com/justinas/nosurf"
1011
"snippetbox.org/pkg/models"
1112
)
1213

1314
type HtmlData struct {
14-
Form interface{}
15-
Path string
16-
Flash string
17-
LoggedIn bool
18-
Snippet *models.Snippet
19-
Snippets []*models.Snippet
15+
CSRFtoken string
16+
Form interface{}
17+
Path string
18+
Flash string
19+
LoggedIn bool
20+
Snippet *models.Snippet
21+
Snippets []*models.Snippet
2022
}
2123

2224
func humanDate(t time.Time) string {
@@ -30,6 +32,8 @@ func (app *App) RenderHtml(w http.ResponseWriter, r *http.Request, page string,
3032

3133
data.Path = r.URL.Path
3234

35+
data.CSRFtoken = nosurf.Token(r)
36+
3337
var err error
3438
data.LoggedIn, err = app.LoggedIn(r)
3539
if err != nil {

glide.lock

Lines changed: 5 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

glide.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ import:
99
- package: golang.org/x/crypto
1010
subpackages:
1111
- bcrypt
12+
- package: github.com/justinas/nosurf

ui/html/base.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ <h1><a href="/">Snippetbox</a></h1>
2020
New Snippet
2121
</a>
2222
<form action="/user/logout" method="POST">
23+
<input type="hidden" name="csrf_token" value="{{.CSRFtoken}}">
2324
<button>Logout</button>
2425
</form>
2526
{{else}}

ui/html/login.page.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<div class="flash">{{.}}</div>
66
{{end}}
77
<form action="/user/login" method="POST" novalidate>
8+
<input type="hidden" name="csrf_token" value="{{.CSRFtoken}}">
89
{{with .Form}}
910
{{with .Failures.Generic}}
1011
<div class="error">{{.}}</div>
@@ -23,7 +24,7 @@
2324
{{end}}
2425
<input type="password" name="password">
2526
</div>
26-
<div>
27+
<div>
2728
<input type="submit" value="Submit">
2829
</div>
2930
{{end}}

ui/html/new.page.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
{{define "page-body"}}
44
<form action="/snippet/new" method="POST">
5+
<input type="hidden" name="csrf_token" value="{{.CSRFtoken}}">
56
{{with .Form}}
67
<div>
78
<label>Title:</label>

ui/html/signup.page.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
{{define "page-body"}}
44
<form action="/user/signup" method="POST" novalidate>
5+
<input type="hidden" name="csrf_token" value="{{.CSRFtoken}}">
56
{{with .Form}}
67
<div>
78
<label>Name:</label>

vendor/github.com/justinas/nosurf/.gitignore

Lines changed: 29 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/justinas/nosurf/.travis.yml

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/justinas/nosurf/LICENSE

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/justinas/nosurf/README.md

Lines changed: 125 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)