justinas / nosurf

CSRF protection middleware for Go.

Home Page:http://godoc.org/github.com/justinas/nosurf

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Seems to be broken with Go 1.7

jack-chung opened this issue · comments

commented

When compiled in Go 1.7, nosurf.Token(r) returns empty string.
I've tried the -gcflags=-ssa=0 as suggested by the 1.7 release note, but it didn't help.
https://golang.org/doc/go1.7

Do you have an example? Are you using WithContext() on the request at all?
On Tue, Aug 30, 2016 at 8:10 PM Jack notifications@github.com wrote:

When compiled in Go 1.7, nosurf.Token(r) returns empty string.
I've tried the -gcflags=-ssa=0 as suggested by the 1.7 release note, but
it didn't help.
https://golang.org/doc/go1.7


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
#35, or mute the thread
https://github.com/notifications/unsubscribe-auth/AABIcLhP1Poj9jHsFqCFN8Cndl2fRfm5ks5qlPCTgaJpZM4JxMBd
.

Tests seem to pass on go version go1.7 linux/amd64. Getting more info would be helpful.

@elithrar good catch on WithContext(): could definitely be the culprit:

func handler(w http.ResponseWriter, r *http.Request) {
    r2 := r.WithContext(...)
    token := nosurf.Token(r2)
}

would definitely return an empty token, as r2 points to a different memory location and thus the context map lookup would fail.

I have been thinking about doing a conditional build for ctxSetReason/ctxSetToken/ctxClear that would leverage r.Context on Go >= 1.7 anyway. Should be a pretty clean fix.

commented

I tested this using the authboss-sample app (unmodified).
https://github.com/go-authboss/authboss-sample
I don't see that it uses WithContext so may be something else. The cookie is set properly, but the hidden csrf field in the form is empty.

commented

Hi, are you able to reproduce this issue under Go 1.7 using the authboss-sample? You can just compile and run it, then go to the login page and view the hidden csrf_token field. You will see that it's empty when compiled under 1.7.

The nosurf README example works for me—unmodified—in Go 1.7. What browser are you testing in, @jack-chung?

@jack-chung The authboss-sample is giving me the following error:

2016/09/04 15:05:32 Failed to validate XSRF Token: The CSRF token in the cookie doesn't match the one received in a form/header.

The form does not (as you say) populate the hidden <input> with the token. I assume the way the example is using nosurf is at fault here, but I don't have the time to check into it.

commented

I am able to narrow this down after testing more. It seems to be caused by the use of gorilla mux.
Taking the nosurf README example code, and changing the main function from:

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

to:

mux := mux.NewRouter()
mux.HandleFunc("/", myFunc)
fmt.Println("Listening on http://127.0.0.1:8000/")
http.ListenAndServe(":8000", nosurf.New(mux))

will reproduce the problem. It works when compiled under Go 1.6, but nosurf.Token returns empty string when compiled under 1.7.

Is this helpful? I looked through the gorilla bug list and there are a few related to go 1.7. They all seem to be related to the use of request.WithContext(), but I'm not sure why the use of mux here would cause a problem.

nosurf does not use the new context, which means that when mux (for Go 1.7)
calls WithContext, the CSRF token in nosurf's map[*http.Request]token is
"islanded" as WithContext performs a shallow copy.

The map key, being the request, no longer points to the correct request.

This problem exists for any library using a global map based on
http.Request + using *any library that uses the new WithContext() shallow
copy. https://github.com/gorilla/csrf uses the new context when built on Go
1.7, and it should be an easy fix for nosurf as well (copy paste, almost).

On Tue, Sep 6, 2016 at 10:11 PM Jack notifications@github.com wrote:

I am able to narrow this now after testing more. It seems to be caused by
the use of gorilla mux.
Taking the nosurf README example code, and changing the main function from:
myHandler := http.HandlerFunc(myFunc)
fmt.Println("Listening on http://127.0.0.1:8000/")
http.ListenAndServe(":8000", nosurf.New(myHandler))

to:
` mux := mux.NewRouter()
mux.HandleFunc("/", myFunc)

fmt.Println("Listening on http://127.0.0.1:8000/")
http.ListenAndServe(":8000", nosurf.New(mux))`

will reproduce the problem. It works when compiled under Go 1.6, but
nosurf.Token returns empty string when compiled under 1.7.

Is this helpful? I looked through the gorilla bug list and there are a few
related to go 1.7. They all seem to be related to the use of
request.WithContext(), but I'm not sure why the use of mux here would cause
a problem.


You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub
#35 (comment), or mute
the thread
https://github.com/notifications/unsubscribe-auth/AABIcJQH7AK1SWZNiv6F0kYOHhCgq2iMks5qnkdkgaJpZM4JxMBd
.

So the plan remains to use conditional compiling to support 1.7's Context. Should solve this whole class of problems. Thanks @elithrar for looking into this.

Hello @justinas; I was wondering if you have a timeline for this fix?

Thanks

@kris-runzer I have the fix outlined. I'll be conservative and say it's coming this week.

Thanks @justinas! I'm having the exact same issue. If it helps, I've used the same approach that @elithrar helpfully created for their csrf and mux packages (using build tags to provide backward compatibility) and it works like a charm.

I'm looking forward to the fix!

Should be fixed as of f57d555, at least from what I can tell from the tests. Will wait for someone to confirm in a real world scenario before closing. @jack-chung @kris-runzer @jordan-wright