Insecure object reference - Session management - Go

Insecure object reference - Session management - Go

Need

Secure session management

Context

  • Usage of Go 1.16 for building efficient and scalable applications
  • Usage of Gin framework for building web applications in Go
  • Usage of net/http for creating a web server in a Node.js application

Description

Non compliant code

        package main

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

var sessions map[string]string

func main() {
	r := gin.Default()
	sessions = make(map[string]string)

	r.POST("/login", func(c *gin.Context) {
		email := c.PostForm("email")
		sessions[email] = "active"
	})

	r.POST("/logout", func(c *gin.Context) {
		email := c.PostForm("email")
		delete(sessions, email)
		c.JSON(http.StatusOK, gin.H{"status": "Logged out"})
	})

	r.Run()
}
        
        

In the code above, we are using a simple map named sessions to manage the sessions of users. The key of the map is the user's email, and the value is the session status.

In the /login route, we are adding an entry to the sessions map when a user logs in. The key is the user's email, and the value is "active".

In the /logout route, we are deleting an entry from the sessions map when a user logs out. The key is the user's email.

The vulnerability in this code is in the /logout route. Any user can log out any other user just by knowing their email. This is because we are not checking if the user who is trying to log out is the one who is currently logged in. This is an example of an Insecure Direct Object Reference (IDOR) vulnerability.

Steps

  • Implement a secure session management mechanism.
  • Use a unique session identifier instead of using the user's email as the session key.
  • Generate a random and unique session ID for each user upon successful login.
  • Store the session ID securely, such as in a secure HTTP-only cookie.
  • Associate the session ID with the user's session data in a secure storage (e.g., database).
  • Verify the session ID on each request to ensure the session is valid and belongs to the authenticated user.
  • Implement proper access controls to prevent unauthorized access to other users' sessions.
  • Ensure that the session ID is invalidated and removed from storage upon logout or session expiration.
  • Regularly rotate session IDs to mitigate session hijacking attacks.
  • Consider implementing additional security measures, such as session expiration and session revocation.

Compliant code

        package main

import (
	"crypto/rand"
	"encoding/base64"
	"github.com/gin-gonic/gin"
	"net/http"
)

var sessions map[string]string

func generateSessionID() string {
	b := make([]byte, 32)
	_, err := rand.Read(b)
	if err != nil {
		panic(err)
	}
	return base64.StdEncoding.EncodeToString(b)
}

func main() {
	r := gin.Default()
	sessions = make(map[string]string)

	r.POST("/login", func(c *gin.Context) {
		email := c.PostForm("email")
		sessionID := generateSessionID()
		sessions[sessionID] = email
		c.SetCookie("session_id", sessionID, 3600, "/", "", false, true)
	})

	r.POST("/logout", func(c *gin.Context) {
		sessionID, _ := c.Cookie("session_id")
		delete(sessions, sessionID)
		c.SetCookie("session_id", "", -1, "/", "", false, true)
		c.JSON(http.StatusOK, gin.H{"status": "Logged out"})
	})

	r.Run()
}
        
        

The updated code now uses a secure session management mechanism. Instead of using the user's email as the session key, a unique session identifier is generated for each user upon successful login. This session ID is generated using a cryptographically secure random number generator and is base64 encoded to create a string that can be used as a key in the sessions map.

The session ID is stored in a secure HTTP-only cookie. This means that the session ID is sent with each request but is not accessible via JavaScript, which helps to prevent session hijacking attacks via cross-site scripting (XSS).

When a user logs out, the session ID is removed from the sessions map and the session cookie is deleted from the user's browser.

This approach ensures that even if an attacker knows a user's email, they cannot close the user's session without knowing the session ID. Furthermore, the session ID is not predictable or guessable due to the use of a secure random number generator.

This code does not implement all possible session management security measures. For example, it does not implement session expiration or session revocation. However, it provides a solid foundation for a secure session management mechanism.

References