nosurf

CSRF protection middleware for Go.

Github stars Tracking Chart

nosurf

Build Status
GoDoc

nosurf is an HTTP package for Go
that helps you prevent Cross-Site Request Forgery attacks.
It acts like a middleware and therefore
is compatible with basically any Go HTTP application.

Why?

Even though CSRF is a prominent vulnerability,
Go's web-related package infrastructure mostly consists of
micro-frameworks that neither do implement CSRF checks,
nor should they.

nosurf solves this problem by providing a CSRFHandler
that wraps your http.Handler and checks for CSRF attacks
on every non-safe (non-GET/HEAD/OPTIONS/TRACE) method.

nosurf requires Go 1.1 or later.

Features

  • Supports any http.Handler (frameworks, your own handlers, etc.)
    and acts like one itself.
  • Allows exempting specific endpoints from CSRF checks by
    an exact URL, a glob, or a regular expression.
  • Allows specifying your own failure handler.
    Want to present the hacker with an ASCII middle finger
    instead of the plain old HTTP 400? No problem.
  • Uses masked tokens to mitigate the BREACH attack.
  • Has no dependencies outside the Go standard library.

Example

package main

import (
	"fmt"
	"github.com/justinas/nosurf"
	"html/template"
	"net/http"
)

var templateString string = `
<!doctype html>
<html>
<body>
{{ if .name }}
<p>Your name: {{ .name }}</p>
{{ end }}
<form action="/" method="POST">
<input type="text" name="name">

<!-- Try removing this or changing its value
     and see what happens -->
<input type="hidden" name="csrf_token" value="{{ .token }}">
<input type="submit" value="Send">
</form>
</body>
</html>
`
var templ = template.Must(template.New("t1").Parse(templateString))

func myFunc(w http.ResponseWriter, r *http.Request) {
	context := make(map[string]string)
	context["token"] = nosurf.Token(r)
	if r.Method == "POST" {
		context["name"] = r.FormValue("name")
	}
	
	templ.Execute(w, context)
}

func main() {
	myHandler := http.HandlerFunc(myFunc)
	fmt.Println("Listening on http://127.0.0.1:8000/")
	http.ListenAndServe(":8000", nosurf.New(myHandler))
}

Manual token verification

In some cases the CSRF token may be send through a non standard way,
e.g. a body or request is a JSON encoded message with one of the fields
being a token.

In such case the handler(path) should be excluded from an automatic
verification by using one of the exemption methods:

	func (h *CSRFHandler) ExemptFunc(fn func(r *http.Request) bool)
	func (h *CSRFHandler) ExemptGlob(pattern string)
	func (h *CSRFHandler) ExemptGlobs(patterns ...string)
	func (h *CSRFHandler) ExemptPath(path string)
	func (h *CSRFHandler) ExemptPaths(paths ...string)
	func (h *CSRFHandler) ExemptRegexp(re interface{})
	func (h *CSRFHandler) ExemptRegexps(res ...interface{})

Later on, the token must be verified by manually getting the token from the cookie
and providing the token sent in body through: VerifyToken(tkn, tkn2 string) bool.

Example:

func HandleJson(w http.ResponseWriter, r *http.Request) {
	d := struct{
		X,Y int
		Tkn string
	}{}
	json.Unmarshal(ioutil.ReadAll(r.Body), &d)
	if !nosurf.VerifyToken(nosurf.Token(r), d.Tkn) {
		http.Errorf(w, "CSRF token incorrect", http.StatusBadRequest)
		return
	}
	// do smth cool
}

Contributing

  1. Find an issue that bugs you / open a new one.
  2. Discuss.
  3. Branch off, commit, test.
  4. Make a pull request / attach the commits to the issue.

Overview

Name With Ownerxtaci/kcp-go
Primary LanguageGo
Program languageGo (Language Count: 2)
Platform
License:MIT License
Release Count136
Last Release Namev5.6.8 (Posted on )
First Release Namev1.0.0 (Posted on )
Created At2015-06-16 06:15:55
Pushed At2024-04-23 14:45:33
Last Commit At2024-04-23 22:45:27
Stargazers Count4k
Watchers Count144
Fork Count718
Commits Count703
Has Issues Enabled
Issues Count200
Issue Open Count48
Pull Requests Count28
Pull Requests Open Count10
Pull Requests Close Count27
Has Wiki Enabled
Is Archived
Is Fork
Is Locked
Is Mirror
Is Private
To the top