volatiletech / authboss

The boss of http auth.
MIT License
3.87k stars 208 forks source link

Do I need CSRF protection for /login endpoint? #247

Open frederikhors opened 5 years ago

frederikhors commented 5 years ago

Issue opened for the creation of a wiki page that summarizes the doubts and problems for newbies (https://github.com/volatiletech/authboss/issues/210).


I know

this question has already been asked so many times, but after hours of searching I still don't have a clear answer to my problem.

Even projects like https://github.com/pillarjs/understanding-csrf have been abandoned and have not answered to new questions and doubts over the years like this.

PROBLEM

Let's say I have:

My back-end is a simply app with these rest endpoints:

  1. POST /login:

    1. accepts JSON body like: {"username": "myname", "password": "mypass"}
    2. verify credentials
    3. if OK gives 200 and create a cookie with session
    4. if NOT gives 401
  2. GET /players:

    1. check session in cookie
    2. if OK gives 200 with {"players": "[...]"}
    3. if NOT gives 401
  3. POST /player/1:

    1. check session in cookie
    2. if OK gives 200 and edit player
    3. if NOT gives 401

My front-end app has:

  1. /login page with a form (with username and password fields) for issue a POST request to back.domain.com/login

  2. /players which request a GET request to back.domain.com/players

  3. a button which issues a POST request to back.domain.com/player/1

QUESTIONS

  1. Do I need CSRF protection in this scenario?

    I think YES, I need because an attacker can issue a request to back.domain.com/player/1 from malicious.site.com and use my session cookie to edit player because I'm logged in (and I still have a session cookie) on my domain.com.

  2. Do I need CSRF protection (e.g. an X-CSRF-Token header) when I the first time login on back.domain.com/login?

    1. In this scenario I still don't have any session cookie in my browser.
    2. And also I don't know where to get my CSRF token for X-CSRF-Token authorization header too.

    I read on https://fractalideas.com/blog/making-react-and-django-play-well-together-single-page-app-model they are creating a dedicated endpoint on back-end for this and they explain it's not a security vulnerability.

I saw in authboss-sample you just add the X-CSRF-TOKEN header on OPTIONS calls.

if *flagAPI {
  // In order to have a "proper" API with csrf protection we allow the options request to return the csrf token that's required to complete the request when using post
  optionsHandler := func(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("X-CSRF-TOKEN", nosurf.Token(r))
    w.WriteHeader(http.StatusOK)
  }

  // We have to add each of the authboss get/post routes specifically because chi sees the 'Mount' above as overriding the '/*' pattern.
  routes := []string{"login", "logout", "recover", "recover/end", "register"}
  mux.MethodFunc("OPTIONS", "/*", optionsHandler)
  for _, r := range routes {
    mux.MethodFunc("OPTIONS", "/auth/"+r, optionsHandler)
  }
}

But why are you using that?

Are you using that token in javascript after the OPTIONS call?

But the very first one call is failing, right?

I'm confused.

What do you think about using the dataInjector func to inject csrf token in json response? In fact it is like when we render csrf token in html. Right?

aarondl commented 5 years ago

@frederikhors Browsers automatically fire off OPTIONS pre-flight requests when they're needed to determine CORS headers.

Note the section on pre-flighted requests here: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

The options handler is a single request, and the login post is a follow-up to that that happens after the options is complete. There is no first request failure happening.

It's actually possible there's a bug here because in order for the browser to send back that header it may have to be specified in the CORS headers.

siredwin commented 3 years ago

For anyone else, Authboss puts CSRF token in the header. If you are importing Authboss into a new server(project), it may be a good idea to put CSRF token in form or somewhere else, or your tokens will fail on both sides. I use echo framework with Authboss and I put token in the form.

e.Use(middleware.CSRFWithConfig(middleware.CSRFConfig{
        TokenLookup: "form:csrf",                        // Please use token in form // authboss puts token in header causing clashes
    }))