A Tale of Two Sessions

Alan Braithwaite

@Caust1c

Segment

 Agenda

  • What is a session anyway?
  • How do they work?
  • Types of Sessions
  • Usage Comparison
  • Tour of Jeff

What is a session?

A web session is a sequence of network HTTP request and response transactions associated to the same user.

What is a Cookie?

Attributes

 

Name, Value

Domain, Path

Expires

 

Secure

HttpOnly

SameSite

How do cookies work?

Server Side Stateful Session

Encrypted Cookie Session

Threat Model Comparison

Encrypted cookies are more secure because they're encrypted

Encrypted cookies are more secure because they're encrypted

An attacker stealing an encrypted cookie still allows them to impersonate a user.

Side note: Always use TLS/HTTPS!

Threat Model Comparison

Secrets Management

Serverside

Encrypted Cookie

None
Databases firewalled

Ultra-secret key
If compromised, attacker can impersonate any user

Threat Model Comparison

Revocation

Serverside

Encrypted Cookie

Delete key in database

???
Choose your own adventure


Will likely end up implementing server-side verification for every request

Encrypted Cookies Benefits

Server to server, request scoped Authentication

"Lazy" authentication as redundant backup

Federated Authentication with JWT

Jeff

A tool for managing Sessions

Jeff

A tool for managing Sessions

p := &redis.Pool{
        MaxIdle:     3,
        IdleTimeout: 240 * time.Second,
        Dial:        func() (redis.Conn, error) {
                return redis.Dial("tcp", "localhost:6379")
        },
}
str := redis_store.New(p)
s := &server{
        jeff: jeff.New(str, jeff.Insecure),
}
router.HandleFunc("/", s.indexPageHandler)
router.HandleFunc("/register", s.registerFormHandler).Methods("GET")
router.HandleFunc("/register", s.registerHandler).Methods("POST")
router.HandleFunc("/login", s.loginHandler).Methods("POST")
router.Handle("/logout", s.jeff.WrapFunc(s.logoutHandler)).Methods("POST")
router.Handle("/internal", s.jeff.WrapFunc(s.internalPageHandler))
router.Handle("/public", s.jeff.PublicFunc(s.publicPageHandler))

http.Handle("/", router)
http.ListenAndServe(":8000", nil)

Jeff

A tool for managing Sessions

func (s *server) loginHandler(w http.ResponseWriter, r *http.Request) {
        name := r.FormValue("name")
        pass := r.FormValue("password")

        user, err := authUser(name, pass)
        if err != nil {
                w.WriteHeader(400)
                return
        }
        err := s.jeff.Set(r.Context(), w, []byte(user.Email))
        if err != nil {
                w.WriteHeader(500)
                panic(err)
        }
        http.Redirect(w, r, "/internal", 302)
}

Jeff

A tool for managing Sessions

// This page won't be reached without an active session if wrapped
// with jeff.Wrap
func (s *server) internalPageHandler(w http.ResponseWriter, r *http.Request) {
        sess := jeff.ActiveSession(r.Context())
        user := loadUser(sess.Key)
        fmt.Fprintf(w, internalPage, user)
}

// This page will be reached without an active session if wrapped
// with jeff.Public.  ActiveSession will return an empty session if there
// is no session.
func (s *server) publicPageHandler(w http.ResponseWriter, r *http.Request) {
        sess := jeff.ActiveSession(r.Context())
        user := loadUser(sess.Key)
        fmt.Fprintf(w, publicPage, user)
}

Jeff

A tool for managing Sessions

$ redis-cli

127.0.0.1:6379> keys *
1) "c@example.com"
2) "a@example.com"
3) "b@example.com"

127.0.0.1:6379>

Thank you

Alan Braithwiate
Segment
@Caust1c
 

https://github.com/abraithwaite/jeff

https://blog.abraithwaite.net/2018/08/14/two-sessions/