Skip to content
This repository has been archived by the owner on Feb 24, 2024. It is now read-only.

CSRF error when Clearing the Session and Redirecting to a form #886

Closed
kteb opened this issue Jan 29, 2018 · 5 comments
Closed

CSRF error when Clearing the Session and Redirecting to a form #886

kteb opened this issue Jan 29, 2018 · 5 comments
Assignees
Labels
bug Something isn't working help wanted Feel free to contribute!
Milestone

Comments

@kteb
Copy link
Member

kteb commented Jan 29, 2018

We discussed the case with @markbates on Slack.

Here is the error:

CSRF token not found in request
github.com/gobuffalo/buffalo.sessionSaver.func1
    /home/kteb/gowork/src/github.com/gobuffalo/buffalo/session.go:72
github.com/gobuffalo/buffalo.RequestLoggerFunc.func1
    /home/kteb/gowork/src/github.com/gobuffalo/buffalo/request_logger.go:51
github.com/gobuffalo/buffalo.(*App).PanicHandler.func1
    /home/kteb/gowork/src/github.com/gobuffalo/buffalo/errors.go:69
github.com/gobuffalo/buffalo.RouteInfo.ServeHTTP
    /home/kteb/gowork/src/github.com/gobuffalo/buffalo/handler.go:75
github.com/gobuffalo/buffalo.(*RouteInfo).ServeHTTP
    <autogenerated>:1

Here is the code I used

func SetCurrentUser(next buffalo.Handler) buffalo.Handler {
    return func(c buffalo.Context) error {
        if uid := c.Session().Get("current_user_id"); uid != nil {
            u := &models.User{}
            tx := c.Value("tx").(*pop.Connection)
            err := tx.Find(u, uid)
            if err != nil {
                if errors.Cause(err) != sql.ErrNoRows {
                    return errors.WithStack(err)
                }
                c.Session().Clear()
                c.Flash().Add("warning", "We didn't find the session you were connected to, so please reconnect")
                return c.Redirect(302, "/signin")
            }
            c.Set("current_user", u)
        }
        return next(c)
    }
}

I'm using the default form generated by auth:

<%= form_for(user, {action: signinPath()}) { %>
  <%= f.InputTag("Email") %>
  <%= f.InputTag("Password", {type: "password"}) %>
  <button class="btn btn-success">Sign In!</button>
<% } %>

I reproduce it with migrating down the db and migrating up and seeding my default user.

From here it's the explanation of Mark on Slack:

i can reproduce, not sure i know what the fix is, but here’s what’s happening:

  • you make a call to clear the session
  • the redirect happens
  • buffalo renders the template, with the CSRF token in it (it’s there, i saw it in the generated HTML)
  • the page is rendered, and the request to delete the session cookie completes

this is where things get interesting.
the page is already rendered with a token, however that token was salted using a salt that was in the session that was clear after the page was drawn; cause cookies.
and that’s how you get a CSRF token in a form but not have it be valid. 🙂
the error message is misleading though.
it was found, but it’s not a valid CSRF token.

the work around would be to just delete the current_user_id from the session, but it would be great if someone can figure out a good way to stop this from happening in the future.

@markbates markbates added this to the 0.11.0 milestone Jan 29, 2018
@markbates markbates added bug Something isn't working help wanted Feel free to contribute! labels Jan 29, 2018
@wwaldbu
Copy link

wwaldbu commented Jan 31, 2018

I am having an issue with this also. I was following the tutorial linked above and I am unable to post from a form to a database without getting:

CSRF token not found in request
github.com/gobuffalo/buffalo.sessionSaver.func1

Here is my render.go file:

package actions

import (
	"html/template"

	"github.com/gobuffalo/buffalo/render"
	"github.com/gobuffalo/packr"
)

var r *render.Engine
var assetsBox = packr.NewBox("../public/assets")

func init() {
	r = render.New(render.Options{
		// HTML layout to be used for all HTML requests:
		HTMLLayout: "application.html",
		// Box containing all of the templates:
		TemplatesBox: packr.NewBox("../templates"),
		AssetsBox:    assetsBox,
		// Add template helpers here:
		Helpers: render.Helpers{
			"csrf": func() template.HTML {
				return template.HTML("<input name=\"authenticity_token\" value=\"<%= authenticity_token %>\" type=\"hidden\">")
			},
		},
	})
}

And here is the register.html file I call it in:

<form action="<%= usersRegisterPath() %>" method="POST" novalidate>
                  <%= csrf() %>
                    <div class="form-group">
                      <label for="email">Email address</label>
                      <input type="email" name="Email" class="form-control" id="email">
                    </div>
                    <div class="form-group">
                      <label for="username">Username</label>
                      <input type="text" name="Username" id="username" class="form-control">
                    </div>
                    <div class="form-group">
                      <label for="pwd1">Password</label>
                      <input name="Password" type="password" class="form-control" id="pwd1">
                    </div>
                    <div class="form-group">
                      <label for="passwordConfirm">Confirm password</label>
                      <input name="PasswordConfirm" type="password" class="form-control" id="passwordConfirm">
                    </div>
                    <button type="submit" class="btn btn-primary btn-block">Register</button>
                </form>

Here is my output:

screen shot 2018-01-30 at 8 26 48 pm

@markbates
Copy link
Member

@wwaldbu your issue is different. Your just not setting the token correctly. If you look at your generated html you’ll see that. Your csrf is returning <%= authenticity_token%> instead of the actual token. Is there a reason you’re not using the form helpers? Those will set the token for you as well as generate all that boiler plate bootstrap code.

The original issue is if you follow a very particular set of steps involving clearing the session first.

@markbates markbates removed this from the 0.11.0 milestone Feb 27, 2018
@stanislas-m stanislas-m self-assigned this Apr 4, 2018
stanislas-m added a commit that referenced this issue Apr 7, 2018
* In the case realToken was regenerated, a scoped redefinition was overriding
    the token to nil.
stanislas-m added a commit that referenced this issue Apr 7, 2018
* In the case realToken was regenerated, a scoped redefinition was overriding
    the token to nil.
@stanislas-m stanislas-m added this to the 0.11.1 milestone Apr 7, 2018
@stanislas-m
Copy link
Member

Fixed with #1011.

stanislas-m added a commit that referenced this issue May 12, 2018
* In the case realToken was regenerated, a scoped redefinition was overriding
    the token to nil.
@BorisLeMeec
Copy link

I have the same problem (not really sure if it is EXACTLY the same, but..)

I'm trying to make an ajax call, and the response is always CSRF token not found in request...

I have no idea what is a CSRF token since I usually do not code in web..

@kteb
Copy link
Member Author

kteb commented Aug 7, 2018

Just to know the goal of the CSRF token: https://en.wikipedia.org/wiki/Cross-site_request_forgery

If you're trying to reach your website from another one, it's normal that it fails. You can deactivate the CSRF middleware, but if your application is going to be on the web I will not recommend it.

Here is an example using Ajax call and Buffalo: https://github.com/gobuffalo/toodo

And FYI:
Support question are better asked in one of the following locations:

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working help wanted Feel free to contribute!
Projects
None yet
Development

No branches or pull requests

5 participants