Weak credential policy - Password Change Limit - Go

Weak credential policy - Password Change Limit - Go

Need

Enforce a password change limit policy to prevent abuse and unauthorized access

Context

  • Usage of Go 1.16 for building high-performance and efficient applications
  • Usage of gin-gonic/gin for building web applications and APIs in Go
  • Usage of net/http for handling HTTP requests and responses in a Node.js application

Description

Non compliant code

        package main

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

var passwordChangeCount = make(map[string]int)

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

	router.POST("/change_password", func(c *gin.Context) {
		username := c.PostForm("username")
		newPassword := c.PostForm("new_password")

		// Assume we have a function to change the password
		changePassword(username, newPassword)
		c.JSON(http.StatusOK, gin.H{"status": "Password changed successfully"})
	})

	router.Run(":8080")
}

func changePassword(username string, newPassword string) {
	// Assume we have a function to change the password in the database
	// db.ChangePassword(username, newPassword)
	passwordChangeCount[username]++
}
        
        

In the above code, we have a simple API server running using the Gin framework. It exposes an endpoint /change_password that accepts POST requests to change a user's password.

The changePassword function is called whenever a POST request is made to the /change_password endpoint. It changes the password for the given username and increments the passwordChangeCount for the user. However, there is no limit on how many times a password can be changed in a day. This is a security vulnerability as it allows an attacker to brute force the password change functionality.

The passwordChangeCount map stores the number of times a user has changed their password but it is never used to limit the number of password changes. This means that an attacker could potentially make unlimited password change requests, which is a serious security risk.

Steps

  • Implement a password change limit policy to restrict the number of password change requests that can be made in a day.
  • Track the number of password change requests made by each user.
  • Before allowing a password change request, check if the user has exceeded the password change limit.
  • If the user has exceeded the limit, reject the password change request and notify the user.
  • Store the password change count for each user in a secure and persistent manner.
  • Consider implementing additional security measures such as rate limiting and account lockout to further protect against password abuse.

Compliant code

        package main

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

const passwordChangeLimit = 3

var passwordChangeCount = make(map[string]int)
var passwordChangeDate = make(map[string]time.Time)

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

	router.POST("/change_password", func(c *gin.Context) {
		username := c.PostForm("username")
		newPassword := c.PostForm("new_password")

		// Check if the user has exceeded the password change limit
		if passwordChangeCount[username] >= passwordChangeLimit && passwordChangeDate[username].Day() == time.Now().Day() {
			c.JSON(http.StatusForbidden, gin.H{"status": "Password change limit exceeded"})
			return
		}

		// Assume we have a function to change the password
		changePassword(username, newPassword)
		c.JSON(http.StatusOK, gin.H{"status": "Password changed successfully"})
	})

	router.Run(":8080")
}

func changePassword(username string, newPassword string) {
	// Assume we have a function to change the password in the database
	// db.ChangePassword(username, newPassword)
	passwordChangeCount[username]++
	passwordChangeDate[username] = time.Now()
}
        
        

The updated code now includes a password change limit policy. This policy restricts the number of password change requests that can be made in a day by each user.

The passwordChangeCount map tracks the number of password change requests made by each user. The passwordChangeDate map stores the date of the last password change request made by each user.

Before allowing a password change request, the code checks if the user has exceeded the password change limit for the current day. This is done by comparing the value in passwordChangeCount for the user with the passwordChangeLimit constant and checking if the date in passwordChangeDate for the user is the current day.

If the user has exceeded the limit, the password change request is rejected, and the user is notified with a "Password change limit exceeded" message.

The changePassword function updates the passwordChangeCount and passwordChangeDate maps each time a password is successfully changed.

This approach ensures that the password change count for each user is stored in a secure and persistent manner. It also provides additional security measures to protect against password abuse.

References