gorilla / securecookie

Package gorilla/securecookie encodes and decodes authenticated and optionally encrypted cookie values for Go web applications.
https://gorilla.github.io
BSD 3-Clause "New" or "Revised" License
690 stars 149 forks source link

securecookie: base64 decode failed - caused by: illegal base64 data at input byte 216 #56

Closed ghost closed 5 years ago

ghost commented 6 years ago

Code

Session store

secret := securecookie.GenerateRandomKey(64)
if secret == nil {
    glg.Fatalf("The system random number generator failed")
}
srv.sessionStore = sessions.NewCookieStore(secret)

Session get

func (s *Server) handleLogin(w http.ResponseWriter, r *http.Request) {
    sess, err := s.sessionStore.Get(r, sessionCookieName)
    glg.Infof("Session is new: %v", sess.IsNew)
    if err != nil {
        glg.Errorf("read session: %v", err)
        sess, err = s.sessionStore.New(r, sessionCookieName)
        if err != nil {
            glg.Errorf("new session: %v", err)
            return
        }
    }
}

Output

2018-08-30 16:59:24     [INFO]: Session is new: true
2018-08-30 16:52:10     [ERR]:  read session: securecookie: base64 decode failed - caused by: illegal base64 data at input byte 216
2018-08-30 16:52:10     [ERR]:  new session: securecookie: base64 decode failed - caused by: illegal base64 data at input byte 216

At the point where this error occurs, the session is new and no data has been written into it's Values whatsoever. I can't explain this error, and hoped maybe one of you can help me here? I'd be happy to provide further information.

elithrar commented 6 years ago

Could you provide a deterministic example I can reproduce, with:

a) A fixed key b) The cookie output written to the response (in the Set-Cookie header) c) The cookie sent on the request (in the Cookie) header?

Please also ensure you're on the latest sessions version.

ghost commented 6 years ago

Concerning the latest sessions version, I use dep and have not explicitely specified a version.

The fixed key:

sessions.NewCookieStore([]byte("abc"))

The cookie: session=MTUzNjIzMDEzOHxEdi1CQkFFQ180SUFBUkFCRUFBQVNQLUNBQUlHYzNSeWFXNW5EQThBRFdGMWRHaGxiblJwWTJGMFpXUUVZbTl2YkFJQ0FBRUdjM1J5YVc1bkRBb0FDSFZ6WlhKdVlXMWxCbk4wY21sdVp3d0hBQVZoWkcxcGJnPT18_5Rav2Wm2UI91m45wj3RuBlLU7x_wxcFSYyYbO5S1AE

The cookie that is sent in the request (same as received): session=MTUzNjIzMDEzOHxEdi1CQkFFQ180SUFBUkFCRUFBQVNQLUNBQUlHYzNSeWFXNW5EQThBRFdGMWRHaGxiblJwWTJGMFpXUUVZbTl2YkFJQ0FBRUdjM1J5YVc1bkRBb0FDSFZ6WlhKdVlXMWxCbk4wY21sdVp3d0hBQVZoWkcxcGJnPT18_5Rav2Wm2UI91m45wj3RuBlLU7x_wxcFSYyYbO5S1AE

If I acquire the cookie and send no cookie in that reqeust, I receive a cookie. As soon as I send the cookie back, I get the error.

elithrar commented 6 years ago

Can you share what version you have pinned at?

I assume this is a browser client? On Thu, Sep 6, 2018 at 3:38 AM TimSatke notifications@github.com wrote:

Concerning the latest sessions version, I use dep and have not explicitely specified a version.

The fixed key:

sessions.NewCookieStore([]byte("abc"))

The cookie:

session=MTUzNjIzMDEzOHxEdi1CQkFFQ180SUFBUkFCRUFBQVNQLUNBQUlHYzNSeWFXNW5EQThBRFdGMWRHaGxiblJwWTJGMFpXUUVZbTl2YkFJQ0FBRUdjM1J5YVc1bkRBb0FDSFZ6WlhKdVlXMWxCbk4wY21sdVp3d0hBQVZoWkcxcGJnPT18_5Rav2Wm2UI91m45wj3RuBlLU7x_wxcFSYyYbO5S1AE

The cookie that is sent in the request (same as received):

session=MTUzNjIzMDEzOHxEdi1CQkFFQ180SUFBUkFCRUFBQVNQLUNBQUlHYzNSeWFXNW5EQThBRFdGMWRHaGxiblJwWTJGMFpXUUVZbTl2YkFJQ0FBRUdjM1J5YVc1bkRBb0FDSFZ6WlhKdVlXMWxCbk4wY21sdVp3d0hBQVZoWkcxcGJnPT18_5Rav2Wm2UI91m45wj3RuBlLU7x_wxcFSYyYbO5S1AE

If I acquire the cookie and send no cookie in that reqeust, I receive a cookie. As soon as I send the cookie back, I get the error.

— You are receiving this because you were assigned. Reply to this email directly, view it on GitHub https://github.com/gorilla/securecookie/issues/56#issuecomment-419047660, or mute the thread https://github.com/notifications/unsubscribe-auth/AABIcHGhmIP8IqvCNsrdHpvo4uZyMnu9ks5uYPsegaJpZM4WTp9_ .

ghost commented 6 years ago

github.com/gorilla/sessions@v1.1.2 github.com/gorilla/securecookie@v1.1.1

It is a REST Client, Google Chrome's ARC

elithrar commented 6 years ago

Attempting to reproduce this:

package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/gorilla/sessions"

    "github.com/gorilla/mux"
)

func main() {
    store := sessions.NewCookieStore([]byte("abc123"))
    r := mux.NewRouter()

    r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        sess, err := store.Get(r, "example")
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }

        if sess.IsNew {
            log.Println("session is new")
        }

        sess.Values["user"] = "elithrar"
        if err := sess.Save(r, w); err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }

        fmt.Fprintln(w, "hello")
    })

    log.Fatal(http.ListenAndServe("localhost:8000", r))
}

Getting the cookie:

➜ penguin ~  curl -sv localhost:8000/   *   Trying ::1...
* TCP_NODELAY set
* connect to ::1 port 8000 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET / HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.52.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Set-Cookie: example=MTUzNjM0NzgyOHxEdi1CQkFFQ180SUFBUkFCRUFBQUp2LUNBQUVHYzNSeWFXNW5EQVlBQkhWelpYSUdjM1J5YVc1bkRBb0FDR1ZzYVhSb2NtRnl8r953Nf0UYWVr-1ckaIzprFqE-ubSw3U8Ypc9lG5AJ84=; Path=/; Expires=Sun, 07 Oct 2018 19:17:08 GMT; Max-Age=2592000
< Date: Fri, 07 Sep 2018 19:17:08 GMT
< Content-Length: 6
< Content-Type: text/plain; charset=utf-8
<
hello
* Curl_http_done: called premature == 0
* Connection #0 to host localhost left intact

Sending the cookie:

➜ penguin ~  curl -sv --cookie "example=MTUzNjM0NzgyOHxEdi1CQkFFQ180SUFBUkFCRUFBQUp2LUNBQUVHYzNSeWFXNW5EQVlBQkhWelpYSUdjM1J5YVc1bkRBb0FDR1ZzYVhSb2NtRnl8r953Nf0UYWVr-1ckaIzprFqE-ubSw3U8Ypc9lG5AJ84=" localhost:8000/
*   Trying ::1...
* TCP_NODELAY set
* connect to ::1 port 8000 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET / HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.52.1
> Accept: */*
> Cookie: example=MTUzNjM0NzgyOHxEdi1CQkFFQ180SUFBUkFCRUFBQUp2LUNBQUVHYzNSeWFXNW5EQVlBQkhWelpYSUdjM1J5YVc1bkRBb0FDR1ZzYVhSb2NtRnl8r953Nf0UYWVr-1ckaIzprFqE-ubSw3U8Ypc9lG5AJ84=
>
< HTTP/1.1 200 OK
< Set-Cookie: example=MTUzNjM0Nzg0MnxEdi1CQkFFQ180SUFBUkFCRUFBQUp2LUNBQUVHYzNSeWFXNW5EQVlBQkhWelpYSUdjM1J5YVc1bkRBb0FDR1ZzYVhSb2NtRnl8GlwEkY3G0f8kveytTR0uq-o7QchaprnGG3GF_otzres=; Path=/; Expires=Sun, 07 Oct 2018 19:17:22 GMT; Max-Age=2592000
< Date: Fri, 07 Sep 2018 19:17:22 GMT
< Content-Length: 6
< Content-Type: text/plain; charset=utf-8
<
hello
* Curl_http_done: called premature == 0
* Connection #0 to host localhost left intact

Notes:

It's unclear why the base64 data is failing to decode correctly. It's worth noting that you don't need to call sessionStore.New - as per the docs for store.Get at https://godoc.org/github.com/gorilla/sessions#CookieStore.Get ->

Get returns a session for the given name after adding it to the registry. It returns a new session if the sessions doesn't exist. Access IsNew on the session to check if it is an existing session or a new one. It returns a new session and an error if the session exists but could not be decoded.

ghost commented 6 years ago

Can you read this cookie the next time you start the server? This should be possible, since the key in the key store hasn’t changed, right?

Because when I do, I get this base64 decode error

On 7. Sep 2018, at 21:18, Matt Silverlock notifications@github.com wrote:

Attempting to repro:

package main

import ( "fmt" "log" "net/http"

"github.com/gorilla/sessions"

"github.com/gorilla/mux" )

func main() { store := sessions.NewCookieStore([]byte("abc123")) r := mux.NewRouter()

r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { sess, err := store.Get(r, "example") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return }

  if sess.IsNew {
      log.Println("session is new")
  }

  sess.Values["user"] = "elithrar"
  if err := sess.Save(r, w); err != nil {
      http.Error(w, err.Error(), http.StatusInternalServerError)
      return
  }

  fmt.Fprintln(w, "hello")

})

log.Fatal(http.ListenAndServe("localhost:8000", r)) } Getting the cookie:

➜ penguin ~ curl -sv localhost:8000/ * Trying ::1...

  • TCP_NODELAY set
  • connect to ::1 port 8000 failed: Connection refused
  • Trying 127.0.0.1...
  • TCP_NODELAY set
  • Connected to localhost (127.0.0.1) port 8000 (#0)

    GET / HTTP/1.1 Host: localhost:8000 User-Agent: curl/7.52.1 Accept: /

    < HTTP/1.1 200 OK < Set-Cookie: example=MTUzNjM0NzgyOHxEdi1CQkFFQ180SUFBUkFCRUFBQUp2LUNBQUVHYzNSeWFXNW5EQVlBQkhWelpYSUdjM1J5YVc1bkRBb0FDR1ZzYVhSb2NtRnl8r953Nf0UYWVr-1ckaIzprFqE-ubSw3U8Ypc9lG5AJ84=; Path=/; Expires=Sun, 07 Oct 2018 19:17:08 GMT; Max-Age=2592000 < Date: Fri, 07 Sep 2018 19:17:08 GMT < Content-Length: 6 < Content-Type: text/plain; charset=utf-8 < hello

  • Curl_http_done: called premature == 0
  • Connection #0 to host localhost left intact Sending the cookie:

➜ penguin ~ curl -sv --cookie "example=MTUzNjM0NzgyOHxEdi1CQkFFQ180SUFBUkFCRUFBQUp2LUNBQUVHYzNSeWFXNW5EQVlBQkhWelpYSUdjM1J5YVc1bkRBb0FDR1ZzYVhSb2NtRnl8r953Nf0UYWVr-1ckaIzprFqE-ubSw3U8Ypc9lG5AJ84=" localhost:8000/

  • Trying ::1...
  • TCP_NODELAY set
  • connect to ::1 port 8000 failed: Connection refused
  • Trying 127.0.0.1...
  • TCP_NODELAY set
  • Connected to localhost (127.0.0.1) port 8000 (#0)

    GET / HTTP/1.1 Host: localhost:8000 User-Agent: curl/7.52.1 Accept: / Cookie: example=MTUzNjM0NzgyOHxEdi1CQkFFQ180SUFBUkFCRUFBQUp2LUNBQUVHYzNSeWFXNW5EQVlBQkhWelpYSUdjM1J5YVc1bkRBb0FDR1ZzYVhSb2NtRnl8r953Nf0UYWVr-1ckaIzprFqE-ubSw3U8Ypc9lG5AJ84=

    < HTTP/1.1 200 OK < Set-Cookie: example=MTUzNjM0Nzg0MnxEdi1CQkFFQ180SUFBUkFCRUFBQUp2LUNBQUVHYzNSeWFXNW5EQVlBQkhWelpYSUdjM1J5YVc1bkRBb0FDR1ZzYVhSb2NtRnl8GlwEkY3G0f8kveytTR0uq-o7QchaprnGG3GF_otzres=; Path=/; Expires=Sun, 07 Oct 2018 19:17:22 GMT; Max-Age=2592000 < Date: Fri, 07 Sep 2018 19:17:22 GMT < Content-Length: 6 < Content-Type: text/plain; charset=utf-8 < hello

  • Curl_http_done: called premature == 0
  • Connection #0 to host localhost left intact — You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.
elithrar commented 6 years ago

The key doesn't change, and so as expected, restarting the server doesn't cause the session to be invalid. I can't reproduce your issue, although I would recommend re-factoring your handler to be simpler - there's no need to create a "new" session on your own. Call store.Get and let it handle it for you.

ghost commented 6 years ago

I hoped NewSession and store would overwrite the „corrupt“ session, otherwise I would have chosen that approach.

On 13. Sep 2018, at 03:14, Matt Silverlock notifications@github.com wrote:

The key doesn't change, and so as expected, restarting the server doesn't cause the session to be invalid. I can't reproduce your issue, although I would recommend re-factoring your handler to be simpler - there's no need to create a "new" session on your own. Call store.Get and let it handle it for you.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.

elithrar commented 6 years ago

Note that any time you call “Save”, the session is still written back to the response.

On Fri, Sep 14, 2018 at 8:24 AM TimSatke notifications@github.com wrote:

I hoped NewSession and store would overwrite the „corrupt“ session, otherwise I would have chosen that approach.

On 13. Sep 2018, at 03:14, Matt Silverlock notifications@github.com wrote:

The key doesn't change, and so as expected, restarting the server doesn't cause the session to be invalid. I can't reproduce your issue, although I would recommend re-factoring your handler to be simpler - there's no need to create a "new" session on your own. Call store.Get and let it handle it for you.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.

— You are receiving this because you were assigned. Reply to this email directly, view it on GitHub https://github.com/gorilla/securecookie/issues/56#issuecomment-421393916, or mute the thread https://github.com/notifications/unsubscribe-auth/AABIcG0Mo-lPEpKmF421SWJaUDbs1fk1ks5ua8oygaJpZM4WTp9_ .

whoiscarlo commented 9 months ago

@elithrar I know this is insanely old but currently facing the same exact issue and I can not figure out what is going on. It was working perfectly fine and one I deleted the session and tried remake it, I start seeing this error.

Has anyone else come across this issue/ bug?

whoiscarlo commented 9 months ago

Found the issue - when I was sending the cookie back to the server the cookie was corrupted because I had deleted/ cleared the "session" but had not removed it from the next/ future request calls to the server.

Valid Cookie received

sessionName=MTUzNjIzMDEzOHxEdi1CQkFFQ180SUFBUkFCRUFBQVNQLUNBQUlHYzNSeWFXNW5EQThBRFdGMWRHaGxiblJwWTJGMFpXUUVZbTl2YkFJQ0FBRUdjM1J5YVc1bkRBb0FDSFZ6WlhKdVlXMWxCbk4wY21sdVp3d0hBQVZoWkcxcGJnPT18_5Rav2Wm2UI91m45wj3RuBlLU7x_wxcFSYyYbO5S1AE

Corrupted Cookie Sent:

sessionName=

This is also a corrupted Cookie

sessionName=undefined