Skip to main content

Concurrent sessions control bypass

Need

Enhancement of concurrent session control mechanism

Context

  • Usage of Go 1.15 for building high-performance and scalable applications
  • Usage of gin-gonic/gin for building web applications in Go
  • Usage of net/http for building HTTP servers in a Node.js application

Description

Non compliant code

package main

import (
"github.com/gin-gonic/gin"
"net/http"
)

func main() {
r := gin.Default()

r.GET("/validURL", func(c *gin.Context) {
session, _ := store.Get(c.Request, "mysession")
if session.IsNew {
session.Save(c.Request, c.Writer)
c.String(http.StatusOK, "New session started")
} else {
c.String(http.StatusOK, "Session already started")
}
})

r.Run(":8080")
}

The above code is a simple Go application using the gin framework. It defines a route handler for a GET request to "/validURL".

In the handler function, it retrieves the session named "mysession". If the session is new, it saves the session and returns a message indicating that a new session has started. If the session is not new, it simply returns a message indicating that a session has already started.

The vulnerability here is that there is no control over concurrent sessions. When a client sends a GET request to "/validURL", even if there is already an existing session, it just returns a message but does not stop the client from continuing to use the application. This means it is possible to bypass the concurrent session control by going to any valid URL in the application when the error that there is already a session started appears.

This is a security risk as it allows for session fixation attacks, where an attacker can hijack a valid user session. The application should not allow multiple active sessions at the same time.

Steps

  • Implement a mechanism to track active sessions for each user.
  • When a new session is started, check if the user already has an active session.
  • If the user already has an active session, invalidate the previous session and start a new one.
  • Ensure that the session is properly saved and updated in the session store.
  • Handle any errors that may occur during session management.

Compliant code

package main

import (
"github.com/gin-gonic/gin"
"net/http"
"github.com/gorilla/sessions"
)

var store = sessions.NewCookieStore([]byte("secret"))

func main() {
r := gin.Default()

r.GET("/validURL", func(c *gin.Context) {
session, _ := store.Get(c.Request, "mysession")
if session.IsNew {
session.Save(c.Request, c.Writer)
c.String(http.StatusOK, "New session started")
} else {
session.Options.MaxAge = -1
err := session.Save(c.Request, c.Writer)
if err != nil {
http.Error(c.Writer, err.Error(), http.StatusInternalServerError)
return
}
newSession, _ := store.New(c.Request, "mysession")
newSession.Save(c.Request, c.Writer)
c.String(http.StatusOK, "Previous session invalidated, new session started")
}
})

r.Run(":8080")
}

The updated code now includes a mechanism to track active sessions for each user. When a new session is started, it checks if the user already has an active session. If the user already has an active session, it invalidates the previous session and starts a new one.

The session invalidation is done by setting the MaxAge option to -1. This tells the browser to delete the session cookie immediately. After invalidating the old session, a new session is created and saved in the session store.

The Save method is used to save the session data in the session store and also to send a new session cookie to the client. If there is an error while saving the session, it is handled by sending an internal server error response to the client.

This way, it is not possible to bypass the concurrent session control by going to any valid URL in the application when the error that there is already a session started appears.

References