Coder Social home page Coder Social logo

gorilla / csrf Goto Github PK

View Code? Open in Web Editor NEW
998.0 27.0 155.0 147 KB

Package gorilla/csrf provides Cross Site Request Forgery (CSRF) prevention middleware for Go web applications & services ๐Ÿ”’

Home Page: https://gorilla.github.io

License: BSD 3-Clause "New" or "Revised" License

Go 98.52% Makefile 1.48%
csrf-protection gorilla middleware golang security csrf xsrf csrf-tokens go gorilla-web-toolkit

csrf's People

Contributors

1046102779 avatar adiabatic avatar apoorvajagtap avatar coreydaley avatar dunglas avatar elithrar avatar euank avatar fjorgemota avatar flexd avatar florianloch avatar francoposa avatar husio avatar jamesgroat avatar jmcarp avatar kevinburke avatar kisielk avatar llitfkitfk avatar maxximino avatar mittonface avatar mna avatar neelance avatar philipithomas avatar salbertson avatar shoenig avatar stefanocoding avatar tflyons avatar wayneashleyberry avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

csrf's Issues

how to invalidate a token?

Hi,

I just started testing this library and noticed that I can reuse a token for the same form. Is there a way to invalidate the tokens already submitted?

csrf.Token() returns an empty token, even though _gorilla_csrf cookie is set

I'm having trouble getting the Token() helper function to work.

I've wrapped my root-level handler with a csrf.Protect handler, which seems to work. The handler rejects requests that don't specify the correct token, and also sets the _gorilla_csrf cookie on GET requests.

But when I use csrf.Token for setting X-CSRF-Token as described in the docs, I get an empty string.

Looking at the function it seems that an empty string will be returned if the context store does not contain the token secret. But I don't understand how that can be when I'm also getting the _gorilla_csrf cookie set to a non-empty value.

Any pointers or clarification would be greatly appreciated.

Multiple Servers Behind Load Balancer

Hi,
This may be an ignorant question but I'm new to implementing my own CSRF token as a middleware.

How would this work if there were multiple app servers behind load balancer being round robined to? Is there a redis or database method of storing and verifying the token instead of doing it server side?

Thank you

Support for more 'safe' methods

The HTTP method registry lists more 'safe' methods than those specified in RFC7231 (mostly from WebDAV).

While WebDAV may be dead, we find ourselves wanting a safe method that supports a request body. REPORT fits this bill nicely. However, the list of safe methods is inflexible, and this appears to be by design (which is why I'm opening an issue for discussion, rather than a PR with the change I'm suggesting).

What do you think about either:

  • adding all safe methods from the HTTP method registry to the whitelist
  • making the whitelist configurable/extendable

My first thought for a workaround was to call csrf.UnsafeSkipCheck(r) in a wrapper around the call to csrf.Protect when I detect the method is REPORT, but that didn't seem to work. When the csrf.Protect middleware ran, it did not find the skipCheckKey on the context. It is possible I was doing something wrong, though.

The workaround I settled on was to pretend REPORT was not safe, and require the CSRF token. This seems to work, but it strikes me as wrong.

Forbidden - CSRF token invalid when changing the "32-byte-long-auth-key" key

Hi There,

I have encountered an issue that whenever I tried to change the "32-byte-long-auth-key" key. It always shows "Forbidden - CSRF token invalid". It was working fine until the "32-byte-long-auth-key" key is changed.

Basically, I have two buttons. One button is for getting the CSRF token. The other button is for submitting data through AJAX. The CSRF token is embedded in the header when submitted the data through AJAX. The issue can be reproduced by the following steps:

  1. Click on "get token" button.
  2. Click on "submit" button.
  3. Repeat Step 1 and Step 2 several times. It's all working fine.
  4. modify "test_form.go" and change "32-byte-long-auth-key" to something else say "38-byte-long-auth-key".
  5. stop and start the Go web server by running: go run github.com/hello/test_form.go
  6. At this point, when I tried to repeat Step 1 and Step 2. It keeps showing "Forbidden - CSRF token invalid".

Note: I've turned on my Chrome developer tools to observer the information in network and console tabs.

I have tried to reset the _gorilla_csrf cookie (value, path, expired date, secure, httponly) on both client and server side without any lucks. The only way to make it working again is to clear the cookies manually in Chrome's setting.

I have observed one thing. When it's getting the 403 forbidden CSRF token error message, the cookie contains multiple _gorilla_csrf cookie names in the requested header. For example:

Cookie:_gorilla_csrf=MTQ1OTIxOTcxM3xJbEZDZVU1dlduaFBhek5TVDNkTU1FNXZka1kwYkZGNVdEbEtTM3AyVWtzeWJrNVRRMFZST1ZJd1FtTTlJZ289fCA3jchCObZSAf3CiVXbDTht4lYPAWGd_BIKKq53BHJK; _gorilla_csrf=MTQ1OTIxOTcxNnxJa0oyWm5wQ1NEUXdhMVphTUhSblVGWmtkMnhVZFVwUlJXdGpaV1ZxY1V4VVkyMU1PRFJFZEVkb1JFRTlJZ289fNWkquJkXj0qW4_VvLwMmBlfBGu7uSTlH5F-w_NDPKYL

Note: I have reproduced this issue several times and it has the same issue in both HTTP and HTTPS. And also take care of csrf.Secure(false) when switch between HTTP/HTTPS.

I would like to know the proper way to deal with this issue. Because I do not want to bother the client to clear the cookie manually each time the site isn't working.

server side script - github.com/hello/test_form.go:

package main

import (
    "fmt"
    "github.com/gorilla/csrf"
    "github.com/gorilla/mux"
    "net/http"
    "encoding/json"
    "strconv"
)

const (
    HTTP_PORT       = ":80"
    CSRF_AUTH_KEY   = "31-byte-long-auth-key"
    STATIC_DIR = "/static/"
)

type RetJson struct {
  Status bool
}

type User struct {
  Uid int
  Name string
  Email string
}

func RootHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/html; charset=utf-8")

    w.Write([]byte("<script src='/static/scripts/jquery-2.2.2.min.js'></script>" +
      "<script src='/static/scripts/test_form.js'></script>"))
}

func SubmitSignupForm(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json; charset=UTF-8")

    // We can trust that requests making it this far have satisfied
    // our CSRF protection requirements.

    retjson := RetJson {}
    retjson.Status = true

    b, err := json.Marshal(retjson)

    if err != nil {
        http.Error(w, err.Error(), 500)
        return
    }

    w.Write(b)
}

func GetUser(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json; charset=UTF-8")

    uid := mux.Vars(r)["uid"] // variable name is case sensitive

    uid2, err := strconv.Atoi(uid)

    fmt.Printf("main(): %s\n", err)

    // Authenticate the request, get the id from the route params,
    // and fetch the user from the DB, etc.
    user := User {Uid: uid2, Name: "Test Name", Email: "[email protected]"}

    // Get the token and pass it in the CSRF header. Our JSON-speaking client
    // or JavaScript framework can now read the header and return the token in
    // in its own "X-CSRF-Token" request header on the subsequent POST.
    w.Header().Set("X-CSRF-Token", csrf.Token(r))

    b, err := json.Marshal(user)

    if err != nil {
        http.Error(w, err.Error(), 500)
        return
    }

    w.Write(b)
}

func main() {
    r := mux.NewRouter()

    r.PathPrefix(STATIC_DIR).Handler(http.StripPrefix(STATIC_DIR, http.FileServer(http.Dir("." + STATIC_DIR))))

    r.HandleFunc("/", RootHandler)

    api := r.PathPrefix("/api").Subrouter()
    api.HandleFunc("/user/{uid}", GetUser).Methods("GET")

    // All POST requests without a valid token will return HTTP 403 Forbidden.
    api.HandleFunc("/signup/post", SubmitSignupForm).Methods("POST")

    err := http.ListenAndServe(HTTP_PORT, csrf.Protect([]byte(CSRF_AUTH_KEY), csrf.Secure(false))(r))

    if err != nil {
        fmt.Printf("main(): %s\n", err)
    }
}

client side script - static/scripts/test_form.js:

$( document ).ready(function() {
  $('body').append('user id: <input id="user_id" value="10"/>');
  $('body').append('<br><br>Token: <input id="token" size="160" />');
  $('body').append('<br><br>ajax-return-data: <textarea id="ajax-return-data" cols="160" rows="5"></textarea>');

  $('body').append('<br><br><button id="getToken">get token</button>');
  $('body').append('&nbsp;&nbsp;<button id="submitBtn">submit</button>');

  $('#getToken').on('click', function(event){
    var _user_id = $('#user_id').val();

    $.ajax({
      url: "/api/user/" + _user_id,
    }).done(function(data, status, xhr) {
      var _token = xhr.getResponseHeader('X-Csrf-Token');

      $('#token').val(_token);
      $('#ajax-return-data').val(JSON.stringify(data));
    }).fail(function(data, status, xhr) {
      console.log(data);
      console.log(status);
    });

  });

  $('#submitBtn').on('click', function(event){
    var _token = $('#token').val();

    $.ajax({
      url: "/api/signup/post",
      method: 'post',
      headers: {'X-CSRF-Token': _token},
      data: {name: 'test', pass: 'test'},
      dataType: 'json',
    }).done(function(data, status, xhr) {
      console.log(data);
      //console.log(xhr.getAllResponseHeaders());
    }).fail(function(data, status, xhr) {
      console.log(data);
      console.log(status);
    });

  });
});

Fixed: Forbidden - CSRF token invalid

Cause: you use http not https to send request
Fixed: if you use http to send request, you need modify a line of code
Steps๏ผš

  1. "github.com/gorilla/csrf/options.go: 118 line
  2. modify "cs.opts.Secure = true" to "cs.opts.Secure = false"
  3. go build && go install , then your project will be ok

FieldName option documentation is incorrect.

FieldName doesn't set csrf.TemplateTag, it sets csrf.opts.FieldName

Corrected docs:

// FieldName allows you to change the name value of the hidden <input> field
// generated by csrf.TemplateField. The default is "gorilla.csrf.Token"
....

Option to make it not consume http body; verify token manually

I have a site where large file uploads through FORMs will be done, thus it would be preferable to first manually parse the request, streaming files out (incase of multipart/form-data), then to call csrf, asking if the request is okay. Reading the request before csrf gets to it (and consumes it) seems excessive.

No 'Max-Age'

If a cookie has no 'Max-Age', it generally expires when the web browser closes.
Golang's Cookie supports this feature.
See https://golang.org/pkg/net/http/#Cookie

Currently gorilla/csrf don't seem to support the feature and set Max-Age to 12 hours instead.
I think gorilla/csrf should not set Max-Age if the user explicitly set the MaxAge option to 0
and should set Max-Age to 12 hours for compatibility if the user don't pass the MaxAge option.

What do you think?

[question] Apply CSRF only to a subrouter

I don't understand how to apply CSRF only to one subrouter.

Example, from the example in the doc:

    r := mux.NewRouter()

    sr1 := r.PathPrefix("/api1").Subrouter()
    sr1.HandleFunc("/user/{id}", ApiFunc).Methods("GET")

    sr2 := r.PathPrefix("/api2").Subrouter()
    sr2.HandleFunc("/user/{id}", AnotherApiFunc).Methods("GET")

    // I want to protect only sr1, not sr2. How to do it?
    http.ListenAndServe(":8000",
        csrf.Protect([]byte("32-byte-long-auth-key"))(r))

Declare an exported type for option functions.

func Option func(*csrf)
func Protect(authKey []byte, opts ...Option) func(http.Handler) http.Handler
func CookieName(name string) Option
...

Benefits:

  • Improved documentation organization. All functions returning Option will be listed under the Option type.
  • Application flexibility. This change will allow applications to declare and construct a slice of options separate from the implicit slice constructed by the variadic call.

Examples should limit requests to POST

In the examples in the documentation at https://github.com/gorilla/csrf/blob/master/README.md and https://github.com/gorilla/csrf/blob/master/doc.go, the handlers do not check that the request method is POST (or other modification request types).

According to the documentation, this package "[o]perates on a 'whitelist only' approach where safe (non-mutating) HTTP methods (GET, HEAD, OPTIONS, TRACE) are the only methods where token validation is not enforced." However, the method used is decided by the client, so unless the server disallows these whitelisted requests, the CSRF protection can be bypassed by changing the method to a GET.

E.g. with the attached example:

go run csrf-example.go&
curl -X GET http://localhost:8000/delete/foo
You've passed the CSRF check!
Deleting foo

Perhaps people should know that they need to check the request method when there's no body, but it would be good to remind people of this by including the check in the examples for this package.
csrf-example.txt

CSRF ๅค„็† multipart/form-data ็š„้—ฎ้ข˜

ๅฝ“ๆ—ถไฝฟ็”จ PathPrefix ็š„ๆ—ถๅ€™๏ผŒCSRF ไผšๅคฑๆ•ˆ๏ผŒๆฏ”ๅฆ‚ไปฅไธ‹ไปฃ็ ๏ผš

CSRF := csrf.Protect(
[]byte("a-32-byte-long-key-goes-here"),
)

router := mux.NewRouter()
router.HandleFunc("/front/", controller.FontIndex)

adminRoutes := mux.NewRouter()
adminRoutes.HandleFunc("/admin/form", controller.AdminForm)

router.PathPrefix("/admin").Handler(negroni.New(
negroni.NewRecovery(),
middleware.NewCheckLogin(),
negroni.Wrap(adminRoutes),
))

n := negroni.New(
negroni.NewRecovery(),
)

n.UseHandler(CSRF(router))

log.Fatal(http.ListenAndServe(":3001", n))

่ฎฟ้—ฎ http://domain/front ,CSRFๆ˜ฏๅฏไปฅ็”จ็š„๏ผŒไฝ†ๅฆ‚ๆžœ่ฎฟ้—ฎ http://domain/admin/form ๏ผŒ่ฟ™ๆ—ถ CSRF ไผšๅคฑๆ•ˆใ€‚

ErrBadToken when rebuilding docker container

Apologies if this description is a bit lacking, but after hours of trying to debug this my head is fried and I'm none the wiser...

I'm running a simple server, in a docker container, on digital ocean.

First deployment went great: CSRF middleware worked as intended without issues!

I then fixed a bug, rebuilt the container, pushed it to the server, and now any request going through the middleware is returning ErrBadToken. Nothing has changed as far as the gorilla/csrf code is concerned.

Clearing browser cookies doesn't fix it, restarting the browser doesn't fix it, but running in a Chrome incognito browser window does fix it.

Note that I can't expect clients to clear their browser cache every time I push a new build.

Any suggestions? I'm hoping there is an obvious fix here that I'm missing.

Thanks!

Why is each CSRF token only valid for one path?

If I want to protect the POST /user/register path with CSRF, I am required to get a CSRF token by performing GET /user/register. A token issued from GET /ping is not valid, even if it is the last request issued. Why is this? Also, why is the same token valid for multiple requests?

Getting token invalid redirection if not creating templates using {{ .csrfField }} method.

Hi,
I am trying to setup the input token field in the form and passing token value from outside without using csrf.TemplateField function, but getting token invalid error.

Any suggestions what should be changed here in the template/function etc. ?

package main

import (
	"fmt"
	"html/template"
	"net/http"

	"github.com/gorilla/csrf"
	"github.com/gorilla/mux"
)

var form = `
    <html>
    <head>
    <title>Sign Up!</title>
    </head>
    <body>
    <form method="POST" action="/signup/post" accept-charset="UTF-8">
    <input type="text" name="name">
    <input type="text" name="email">
    <!--
      This is where I am creating my own tag, rather than using TemplateField function.
    -->
    <input type="hidden" name="gorilla.csrf.Form" value={{.tokenValue}}>
    <input type="submit" value="Sign up!">
    </form>
    </body>
    </html>
    `

var t = template.Must(template.New("signup_form.tmpl").Parse(form))

func main() {
	r := mux.NewRouter()
	r.HandleFunc("/signup", ShowSignupForm)
	r.HandleFunc("/signup/post", SubmitSignupForm)
	http.ListenAndServe(":8000",
		csrf.Protect([]byte("32-byte-long-auth-key"), csrf.Secure(false))(r))
}

func ShowSignupForm(w http.ResponseWriter, r *http.Request) {
	t.ExecuteTemplate(w, "signup_form.tmpl", map[string]interface{}{
		"tokenValue": csrf.Token(r),
	})
}

func SubmitSignupForm(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Successful")
}

complete example

I can't quite get the example to work, and I keep getting Forbidden - CSRF token invalid. I'm using HTML form as illustrated and I did see an hidden input field of gorilla.csrf.Token with its value.

am I missing something? can there be a complete example? thank you~

ps. I even tried the example here:
http://www.gorillatoolkit.org/pkg/csrf

Forced errors dependency

Hello,

I noticed that gorilla/csrf is using github.com/pkg/errors which while I believe it is an excellent package, it forces an unnecessary dependency on projects that want to use gorilla/csrf without pkg/errors.

Are there any plans to remove this dependency?

Thanks

[question]: Ability to ignore certain POST requests ?

I want to have an API structure like this

(unauthenticated)
/register
/login

(authenticated)
/logout
/api/*

But since both /register and /login will send data to the server, I want them to be POST requests. Now IIUC, csrf will verify all POST requests, and also it will match the cookie only for the path and its subpaths from which it was originally issued.

Otherwise, my endpoints will look like /login/api/dothis, /login/api/dothat which will make it look very weird.

I guess I have 2 questions -

  1. Is it possible to ignore validation on certain POST requests ?
  2. Is it possible to use a token from one path on another path ?

Keep getting: Forbidden - CSRF token invalid - using example

Hi,

I must be doing something really wrong but running the example from
http://www.gorillatoolkit.org/pkg/csrf

keeps giving me Forbidden - CSRF token invalid

the only changed I made to the example was to use

csrf.Protect([]byte("keep-it-secret-keep-it-safe-----"))(r))

in the post request, I see the name, email fields being submitted, and also

gorilla.csrf.Token: XrNHtAeI5BWdNniozRfxNXjv65myi/Lo6GhCqED1cHXLgpYjSJmyROznxCqjwvB9sRZiiGNMbqkIAtBwPIvQcw==

I added some logging to

https://github.com/gorilla/csrf/blob/master/csrf.go#L181

and I see that realToken is always []

I'm running this on http://localhost:8000/ and made sure to delete all cookies between runs in case I was in some kind of bad state

Thank you.

How do you do key rotation?

Is there a way we can rotate the 32 byte long key? instead of forcing users to logout and log back in to use the new key?

Forbidden - CSRF token invalid when using curl

I am in a dev environment and I am trying to play around with the middleware to get it to validate with curl but I cannot do it. I may be missing something simple.

var (
	CSRF = csrf.Protect(
		[]byte(`secret--secret--secret--secret--`),
		csrf.Secure(false),
		csrf.CookieName("csrf"),
	)
)

// using a library called alice to add middlewares...
	// Giving the routes a chain of middleware
	r = alice.New(
		context.ClearHandler,       // clears gorilla sessions memory leak
		handlers.RecoveryHandler(), // recovers from panics
		h.Sessions,                 // for tracking user sessions
		CSRF,                       // adding CSRF protection to responses
		h.Common,                   // adds common headers, other random things
	).Then(r)

if I first do a regular curl to a page I get...

~$ curl -vX GET 127.0.0.1:8080/user/dashboard --cookie "session=MTQ4OTQ4Mjg3M3xTV0ZyckFyOVhWU3NuN2tWTzBkcEVoWWdnRGNpRmdRakNOUGtxUXF2WmxPOXJxejZPRVR5NlJLdk9LeXR6N183RV9EekpJZ0FqcmUzLU5HV3R3PT18YFar7QU2OgDFw9Bze35bOvPKQlINwGnU8Ct55VUeDZY="
Note: Unnecessary use of -X or --request, GET is already inferred.
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> GET /user/dashboard HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.51.0
> Accept: */*
> Cookie: session=MTQ4OTQ4Mjg3M3xTV0ZyckFyOVhWU3NuN2tWTzBkcEVoWWdnRGNpRmdRakNOUGtxUXF2WmxPOXJxejZPRVR5NlJLdk9LeXR6N183RV9EekpJZ0FqcmUzLU5HV3R3PT18YFar7QU2OgDFw9Bze35bOvPKQlINwGnU8Ct55VUeDZY=
> 
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=UTF-8
< Set-Cookie: csrf=MTQ4OTU2OTgzMnxJamxKYkVORU5tbFJTMVpFVDNoblMzSjJNRGRGVG1nNVFVdEdObVl5ZEd0aE4xQk5NRWhyVUdGQ1N6QTlJZ289fBVAyXeIJScwZd8vkCX7VMvHWzERDZA7PGmSZuUeeHms; HttpOnly
< Vary: Cookie
< Date: Wed, 15 Mar 2017 09:23:52 GMT
< Content-Length: 29
< 
{"response":"Hi There UserName"}
* Curl_http_done: called premature == 0
* Connection #0 to host 127.0.0.1 left intact

and then if I use the received CSRF token to add an X-CSRF-Token header it fails to validate...

~$ curl -vX POST http://127.0.0.1:8080/user/update --cookie "session=MTQ4OTQ4Mjg3M3xTV0ZyckFyOVhWU3NuN2tWTzBkcEVoWWdnRGNpRmdRakNOUGtxUXF2WmxPOXJxejZPRVR5NlJLdk9LeXR6N183RV9EekpJZ0FqcmUzLU5HV3R3PT18YFar7QU2OgDFw9Bze35bOvPKQlINwGnU8Ct55VUeDZY=" --header "X-CSRF-Token: csrf=MTQ4OTU2OTI0NHxJbVl5VXpCSVRVbEVPVTl4YTA1blNsRktXWFpwT0V4MWJrUmhURWQ2UzJaa1dHMDVNbEJEYXpaQ2RtczlJZ289fDH39yldTHauDN4dQ8LVTK93RUTWkWKrURIVjSxQHOZ3; HttpOnly"
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> POST /user/update HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.51.0
> Accept: */*
> Cookie: session=MTQ4OTQ4Mjg3M3xTV0ZyckFyOVhWU3NuN2tWTzBkcEVoWWdnRGNpRmdRakNOUGtxUXF2WmxPOXJxejZPRVR5NlJLdk9LeXR6N183RV9EekpJZ0FqcmUzLU5HV3R3PT18YFar7QU2OgDFw9Bze35bOvPKQlINwGnU8Ct55VUeDZY=
> X-CSRF-Token: csrf=MTQ4OTU2OTI0NHxJbVl5VXpCSVRVbEVPVTl4YTA1blNsRktXWFpwT0V4MWJrUmhURWQ2UzJaa1dHMDVNbEJEYXpaQ2RtczlJZ289fDH39yldTHauDN4dQ8LVTK93RUTWkWKrURIVjSxQHOZ3; HttpOnly
> 
< HTTP/1.1 403 Forbidden
< Content-Type: text/plain; charset=utf-8
< Set-Cookie: csrf=MTQ4OTU2OTk1MnxJa3QxV25aVE4wOVljbE5PUjJWMWNtdExkamRJUkZCVFUzVXJRbHBrY3pKa1QwdHRNWFV4TkhkRGJXTTlJZ289fDuSrugP1Up8fqYml7YUtbnw5iMfZhKHobudL9LCly9x; HttpOnly
< X-Content-Type-Options: nosniff
< Date: Wed, 15 Mar 2017 09:25:52 GMT
< Content-Length: 31
< 
Forbidden - CSRF token invalid
* Curl_http_done: called premature == 0
* Connection #0 to host 127.0.0.1 left intact

I have tried all variations I could think of using csrf=<token>; HttpOnly, <token>, csrf=<token>, adding the csrf to the cookie header in the response, etc. Can you see any reason why this would not be working?

gorilla/csrf vs justinas/nosurf

Hi, I'm such a big fan of gorilla/sessions and securecookie.. in my previous project I've been using nosurf but I just discovered your csrf package..

Now I'm working on a new project using the pressly/chi router, and I was hoping you could share your expert opinion about whether any of these packages are more secure/performant than the other, or if it just comes down to personal taste?

Getting "nil" forbidden reason

On a POST request, I'm getting a "nil" forbidden reason. I've been trying to debug this for days, and I can't figure it out. It's only in our production environment. I can't reproduce in staging. A signing token of 32 bytes is set. The system panics if the signing token is zero length.

Forbidden - %!s(<nil>)

Here's my config:

	CSRF := csrf.Protect(
		[]byte(signingToken),
		csrf.Domain(config.ExternalApex), // will be staffjoy.com
		csrf.Secure(!config.Debug), // Will be "true" in prod
		csrf.Path("/"), // I did this because I suspected 
		//csrf.ErrorHandler(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		//	logger.Infof("failed CSRF - %s", csrf.FailureReason(req))
		//	errorpages.Forbidden(res)
		//})),
		csrf.FieldName("csrf"),
	)

Production page with the error is https://www.staffjoy.com/ with the path /early-access/. Other paths seem unaffected (hence my modification of csrf.Path).

Any ideas?

gorilla-csrf sometimes sets two cookies, breaking CSRF validation

Twice now in production, we've run into a problem where people end up with two CSRF cookies, which randomly breaks validation of those cookies. I haven't been able to reproduce this in any lab setting, but I think this may be related to key rotation (e.g. #65), as those were test deployments that had a different CSRF key set.

Would it be possible for the error response emitted from a CSRF validation failure to cause any invalid cookie to be deleted?

Poor interaction with HTTP/2 server push

I'm trying to use HTTP/2 server push and getting an interaction like this:

  • Request 1 comes in

  • Server starts to push requests 2 and 3 to the client.

  • Server starts processing requests 2 and 3 (which do not have the cookie set)

  • gorilla/CSRF sets a cookie on request 1, generates a CSRF token based on that cookie, and sends it to the client

  • requests 2 and 3 try to set a different cookie on the response, overriding that from request 1.

The result is a CSRF mismatch. Any ideas how to handle this?

I could limit it to requests that are not pushed to the client, but protecting some resources and not others is a little tricky with a ServeMux.

How to update the secure cookie

Is there a way to update the secure cookie from the Go application after the Protect Function was called?

The authKey in my application can be changed by another go application, and I'd like to update the secure cookie to use the new authKey once my app realized that the authKey has been changed.
Restarting the whole HTTP server would be kind of difficult

Thank you

Support per-session tokens?

My understanding is that the current implementation generates unique per-request tokens. I find this impractical to work with in complex clients where multiple concurrent AJAX requests are generated. I don't really see why generating per-request tokens is any more secure than generating per-session ones. If a session is highjacked the leakage of the CSRF token is the least of my concerns.

Skipping CSRF check for certain requests?

Say I have an endpoint /destroy-moon whereby the credentials of the client are determined by either (a) a secure session value, or (b) the Authorization header. I obviously want to use CSRF protection in the first case, but not necessarily in the second.

The current design means the only way to skip CSRF validation in the second case requires calling Protect in the handler every time a request is received. This seems sub-optimal, as the Protect call returns a function that performs a fair bit of initialisation that should really only need to be performed once, not every request.

The quick solution would be to expose a func (cs *csrf) Handle(w http.ResponseWriter, r *http.Request, h http.Handler) function, which, rather than calling the handler cs.h, calls the handler h. However, this would make the http.Handler passed to the func returned by Protect completely redundant, and has other ramifications that would upset the nice, clean design of the current library...

So I'm wondering, is this intentional, or have I missed a way to achieve the behaviour I'm after?

SPA cookie expire question

Hi, I'm using your framework to protect REST API which I use from React SPA. I've read from other issues you recommend to put CSRF token to <meta> tag of index.html. So I have a question: How will my SPA get new CSRF token when the first one from <meta> tag is expired?

Generate token without being protected?

We're working with a static SPA and a JSON api backend written in go.

When an authentic set of credentials are posted to /authenticate, a secure http-only cookie is set (for authentication purposes), and - hopefully - a CSRF token is returned in the json body. The SPA stores the csrf token, and sends it with each subsequent api request in the header.

The /authenticate handler should not be CSRF protected, yet it needs to return a CSRF token. Can gorilla csrf do this? I can't seem to generate a token in a handler without that handler also being protected...

Thoughts?

Ability to manually expire cookie

In response to things like a user logout, I believe that it makes sense to expire the CSRF cookie in concert with others that were used for the login session.

Would it make sense for this library to provide a way to do that explicitly?

Demo always given Forbidden - CSRF token invalid

Hey,

I tried to use this package and on form submission, I am getting

'Forbidden - CSRF token invalid'

I thought it may be something to do with the way I set up my application so I used the sample application provided in the docs and I still receive the same error.

I can see the token in the hidden field is the same as that on the submitted form but differ when later retrieved and compared.

csrf will block http.handle

hello, i meet some question when i use csrf to my http server

before my http server ListenAndServ , i excute the http.handle function to set the css directory

r.Handle("/css/", http.StripPrefix("/css/", http.FileServer(http.Dir("./css"))))

CSRF := csrf.Protect([]byte("xxx"),) http.ListenAndServe(":8080", CSRF(r))

then i found ,the handler will be disable by the csrf , css can't be loaded , if i change to

http.ListenAndServe(":8080", nil)

the css can be loaded

so ,how to fix?

Can't get testing environment to work

Hi all; I have csrf working successfully when I go live. And it's awesome! However, I can't get it to work while testing.

Here's basically the testing code:

		t.Run("SignUpHandlerPost", func(t *testing.T) {

			req, err := http.NewRequest("GET", "/signup", nil)
			if err != nil {
				t.Error(err)
			}

			rr := httptest.NewRecorder()
			handler := http.Handler(csrf.Protect(CSRFKey, csrf.Secure(false))(http.HandlerFunc(SignUpHandlerGet)))

			handler.ServeHTTP(rr, req)

			if rr.Code != http.StatusOK {
				t.Errorf("Expected: %v. Got: %v", http.StatusOK, rr.Code)
			}

			fmt.Printf("%+v\n", rr.Result().Cookies())
                        // this uses the html package to find the form gorilla.csrf.Token value
			cs, err := getCSRFTokenFromHTML(rr.Body.String())
			if err != nil {
				t.Error(err)
			}
			fmt.Println(cs)

			form := url.Values{}
			form.Set("gorilla.csrf.Token", cs)
			form.Set("inputPassword", "PASSWORD")
			form.Set("inputEmail", "[email protected]")

			newReq, err := http.NewRequest("POST", "/signup", strings.NewReader(form.Encode()))
			if err != nil {
				t.Error(err)
			}
                        // This adds the base token cookie
			newReq.AddCookie(rr.Result().Cookies()[0])

			newRr := httptest.NewRecorder()
			newHandler := http.Handler(csrf.Protect(CSRFKey, csrf.Secure(false))(http.HandlerFunc(SignUpHandlerPost)))

			newHandler.ServeHTTP(newRr, newReq)
			if newRr.Code != http.StatusOK {
				fmt.Println(newRr.Body.String())
				t.Errorf("Expected: %v. Got: %v", http.StatusOK, newRr.Code)
			}

                        //further test logic
		})

And I still get Forbidden: CSRF token invalid

The cookie is being sent, and as far as I can tell the form values are being sent in the POST request body. Is there supposed to be some sort "store" on the server side that I haven't initialized in my tests?

CSRF token invalid on path prefix "/ru/..." in Chrome

Completely having no ideas whats going on. If path of form begins with "/ru/..." I've got an error while posting data. Maybe this somehow relates to current locale, but this behavior seems weird. Firefox has no such issues.

package main

import (
    "fmt"
    "html/template"
    "net/http"

    "github.com/gorilla/csrf"
    "github.com/gorilla/mux"
)

var form = `
<html>
<head>
<title>Sign Up!</title>
</head>
<body>
<form method="POST" action="/signup/post" accept-charset="UTF-8">
<input type="text" name="name">
<input type="text" name="email">
<!--
The default template tag used by the CSRF middleware .
This will be replaced with a hidden <input> field containing the
masked CSRF token.
-->
{{ .csrfField }}
<input type="submit" value="Sign up!">
</form>
</body>
</html>
`

var t = template.Must(template.New("signup_form.tmpl").Parse(form))

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/signup", ShowSignupForm)                // OK
    r.HandleFunc("/en/account/signup", ShowSignupForm)     // OK
    r.HandleFunc("/ru/account/signup", ShowSignupForm)     // FAIL! Forbidden - CSRF token invalid
    r.HandleFunc("/r/account/signup", ShowSignupForm)      // OK
    r.HandleFunc("/rus/account/signup", ShowSignupForm)    // OK
    r.HandleFunc("/ro/account/signup", ShowSignupForm)     // OK
    r.HandleFunc("/account/ru/signup", ShowSignupForm)     // OK
    // All POST requests without a valid token will return HTTP 403 Forbidden.
    r.HandleFunc("/signup/post", SubmitSignupForm)

    // Add the middleware to your router by wrapping it.
    http.ListenAndServe(":8000",
    csrf.Protect([]byte("32-byte-long-auth-key"))(r))
    // PS: Don't forget to pass csrf.Secure(false) if you're developing locally
    // over plain HTTP (just don't leave it on in production).
}

func ShowSignupForm(w http.ResponseWriter, r *http.Request) {
    // signup_form.tmpl just needs a {{ .csrfField }} template tag for
    // csrf.TemplateField to inject the CSRF token into. Easy!
    t.ExecuteTemplate(w, "signup_form.tmpl", map[string]interface{}{
        csrf.TemplateTag: csrf.TemplateField(r),
    })
}

func SubmitSignupForm(w http.ResponseWriter, r *http.Request) {
    // We can trust that requests making it this far have satisfied
    // our CSRF protection requirements.
    fmt.Fprintf(w, "%v\n", r.PostForm)
}

MaxAge doesn't allow 0 but has code to handle 0 case

The handling of MaxAge is confusing with respect to 0 or negative ages.

In csrf.go:

if cs.opts.MaxAge < 1 {
     // Default of 12 hours
cs.opts.MaxAge = defaultAge
}

In store.go:

// Set the Expires field on the cookie based on the MaxAge
if cs.maxAge > 0 {
    cookie.Expires = time.Now().Add(
        time.Duration(cs.maxAge) * time.Second)
} else {
    cookie.Expires = time.Unix(1, 0)
}

Perhaps we just remove the if condition in store.go?

Using http.Request.Context breaks compatibility with gorilla/mux

Using http.Request.Context() in this package breaks compatibility with any other code that uses gorilla/context (e.g. gorilla/mux). http.Request.WithContext() makes a new http.Request object, which messes up gorilla/context since gorilla/context stores its context values by the *http.Request pointer.

Seems like my only option is to use an older version of gorilla/csrf?

Set csrf.Path differently based on request

Hi,

is it possible to instruct csrf.Protect() in such a way that I can set the csrf.Path option on a request basis?
I don't want the default behavior (using the request path as cookie path), rather I'd like to check each incoming request path against a list of predefined paths. If the request path contains one of these it would be used, otherwise it'd use the request path.

I found that I can pass a csrf.Path Option to csrf.Protect(), but this option is only parsed once and I didn't find a way to observe the current request for setting the path.

Is it possible to inject this kind of handler/middleware at some point so I can implement this behavior?

Thanks!

Forbidden - CSRF token invalid

Hi I'm getting a Forbidden "token invalid" 403 response even though the token is correct.

Here I'm setting the token in my store when the app loads:

    function () {
      fetch(apiURL, {
        method: 'GET'
      })
        // .then(response => console.log(response.headers.get('X-CSRF-Token')))
        .then(response => this.setCSRFToken(response.headers.get('X-CSRF-Token')))
    }

Here I'm sending a POST request (along with the gorilla_csrf cookie) from the domains /login route.

      fetch(apiURL, {
        method: 'POST',
        credentials: 'include',
        headers: {
          'X-CSRF-Token': this.token
        },

Here's the Request being sent:

x-csrf-token: fzMz+oxy0boOITi1GwX36Jq9zhIIp5Zcy30B6gAucyDCsbWc7D7ysHezSq7qD61iAj6sMoz+uUmymMZJ8jE5+Q==
content-type: text/plain;charset=UTF-8
origin: http://localhost:3030
Content-Length: 51
Cookie: _gorilla_csrf=MTUyODA1MjI5M3xJbTVTYWxCbGJuUk1VWGQzYVM4Mll6WmhRbXBKVDNOMFVrRXlaVVZ2VEM4MVNGSjRWbmwwV1hCcFpUZzlJZ289fJPKHLOD_-ckXHtzjS04npF3SEc0usqBDJl8COBW6XZc; scheduler-session=MTUyODA3MDExOHxOd3dBTkZWRFNUWkRUMU5YTlZGSFQwRkRWVVpTVkU5Q1RrMUtTRlpJU1VST1NrMVRTRkJPUjFCVlVWRlFNMW8wUmxOV1JGbEVTbEU9fBMnxfc2ZqhJtakQ_RS316Uu_ACUk1Xv-Nz0LLd8gxPK

Is there additional debugging or output I can enable to help troubleshoot?

Panic on appengine

Taken from README about AppEngine

package app

// Remember: appengine has its own package main
func init() {
    r := mux.NewRouter()
    r.HandleFunc("/", IndexHandler)
    // ...

    // We pass our CSRF-protected router to the DefaultServeMux
    http.Handle("/", csrf.Protect([]byte(your-key))(r))
}

It does not occur panic ?

Reason

http: multiple registrations for /

csrf.go:156

Hello,

When I try to get csrf, I have this error under Go 1.8.1.

go get github.com/gorilla/csrf
# github.com/gorilla/csrf
..\github.com\gorilla\csrf\csrf.go:156: cs.sc.SetSerializer undefined (type *securecookie.SecureCookie has no field or method SetSerializer)
..\github.com\gorilla\csrf\csrf.go:156: undefined: securecookie.JSONEncoder

go version go1.8.1 windows/amd64

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.