Insecure session management - Change Password - Go

Insecure session management - Change Password - Go

Need

Secure session management after password change

Context

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

Description

Non compliant code

        package main

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

type ChangePasswordForm struct {
	OldPassword     string `form:"old_password" binding:"required"`
	NewPassword     string `form:"new_password" binding:"required"`
	ConfirmPassword string `form:"confirm_password" binding:"required"`
}

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

	r.POST("/change_password", func(c *gin.Context) {
		var form ChangePasswordForm
		if err := c.ShouldBind(&form); err == nil {
			// Check if old password is correct
			// If correct, change password
			// Note: No session invalidation after password change
		} else {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		}
	})

	r.Run() // listen and serve on 0.0.0.0:8080
}
        
        

The above Go code uses the Gin web framework to handle a POST request to the /change_password endpoint. This endpoint accepts a form of ChangePasswordForm type, which contains the old password, new password, and a confirm new password field.

The vulnerability in the code is that after the password change, the session remains open. In other words, the user's session is not invalidated after their password is changed. This is a security issue because if an attacker has gained access to a user's session (e.g., via session hijacking), they would continue to have access to the user's account even after the user changes their password.

The code should be modified to invalidate the user's session after a password change. This would force all clients to re-authenticate, thereby preventing any attackers who have gained access to the session from continuing to have access.

Steps

  • Implement session management to track user sessions
  • Generate a unique session ID for each user session
  • Store the session ID securely (e.g., in a secure HTTP-only cookie)
  • Invalidate the session after a password change
  • Upon password change, force the user to re-authenticate and create a new session
  • Ensure the session ID is regenerated upon successful password change
  • Use secure password storage mechanisms (e.g., bcrypt) to store passwords
  • Implement strong password policies and enforce password complexity
  • Regularly review and update the session management implementation for any security vulnerabilities

Compliant code

        package main

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

type ChangePasswordForm struct {
	OldPassword     string `form:"old_password" binding:"required"`
	NewPassword     string `form:"new_password" binding:"required"`
	ConfirmPassword string `form:"confirm_password" binding:"required"`
}

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

	store := cookie.NewStore([]byte("secret"))
	r.Use(sessions.Sessions("mysession", store))

	r.POST("/change_password", func(c *gin.Context) {
		var form ChangePasswordForm
		if err := c.ShouldBind(&form); err == nil {
			// Check if old password is correct
			// If correct, change password

			// Invalidate the session after password change
			session := sessions.Default(c)
			session.Clear()
			session.Save()

			// Force the user to re-authenticate and create a new session
			// Ensure the session ID is regenerated upon successful password change
		} else {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		}
	})

	r.Run() // listen and serve on 0.0.0.0:8080
}
        
        

The updated code now includes session management using the github.com/gin-contrib/sessions package. A unique session ID is generated for each user session and stored securely in a HTTP-only cookie.

When a user changes their password, the current session is invalidated by calling session.Clear() and session.Save(). This forces the user to re-authenticate and a new session is created.

This mitigates the risk of session hijacking, where an attacker could use an old session ID to gain unauthorized access to the application after a user has changed their password.

In addition, the application should also implement secure password storage mechanisms (e.g., bcrypt) to store passwords and enforce strong password policies to further enhance security. Regular reviews and updates of the session management implementation should also be conducted to address any potential security vulnerabilities.

References