Weak credential policy - Password Change Limit
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.