Weak credential policy - Password strength - Go

Weak credential policy - Password strength - Go

Need

Implementation of a strong password policy

Context

  • Usage of Go 1.16 for developing high-performance and efficient applications
  • Usage of gin-gonic/gin 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"
)

func main() {
	r := gin.Default()
	r.POST("/login", func(c *gin.Context) {
		username := c.PostForm("username")
		password := c.PostForm("password")

		// Weak password policy: Any password is accepted
		if username != "" && password != "" {
			c.JSON(http.StatusOK, gin.H{
				"message": "Logged in",
			})
			return
		}

		c.JSON(http.StatusBadRequest, gin.H{
			"message": "Bad request",
		})
	})
	r.Run(":8080")
}
        
        

The above code represents a simple login endpoint in a Go backend application using the Gin framework. The endpoint accepts a POST request with a username and password.

The vulnerability lies in the password validation. Currently, the code only checks if the username and password fields are not empty. This means that any non-empty password is accepted. There are no checks for password length, complexity, or common patterns. This is a weak credential policy, which makes the system more susceptible to brute force attacks.

A strong password policy should enforce rules such as minimum length, a mix of upper and lower case letters, inclusion of numbers and special characters, and not matching common patterns or easily guessable passwords.

Steps

  • Implement a strong password policy that enforces minimum password length
  • Require the use of complex passwords that include a combination of uppercase and lowercase letters, numbers, and special characters
  • Implement password complexity checks to ensure that the password meets the required criteria
  • Consider implementing additional security measures such as password expiration and account lockout after multiple failed login attempts

Compliant code

        package main

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

func main() {
	r := gin.Default()
	r.POST("/login", func(c *gin.Context) {
		username := c.PostForm("username")
		password := c.PostForm("password")

		// Strong password policy: Password must be at least 8 characters long, 
		// include at least one uppercase letter, one lowercase letter, one number, and one special character
		passwordRegex := `^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$`
		match, _ := regexp.MatchString(passwordRegex, password)

		if username != "" && match {
			c.JSON(http.StatusOK, gin.H{
				"message": "Logged in",
			})
			return
		}

		c.JSON(http.StatusBadRequest, gin.H{
			"message": "Bad request",
		})
	})
	r.Run(":8080")
}
        
        

The updated code now includes a strong password policy. This policy is enforced by a regular expression that checks if the password meets the following criteria:

- At least 8 characters long
- Includes at least one uppercase letter
- Includes at least one lowercase letter
- Includes at least one number
- Includes at least one special character

The regexp.MatchString function is used to check if the password matches the regular expression. If the password does not meet these criteria, the server will respond with a "Bad request" message. This ensures that only passwords that meet the strong password policy are accepted by the system.

Please note that this is a basic implementation and does not include additional security measures such as password expiration and account lockout after multiple failed login attempts. For a production system, consider implementing these additional measures to further enhance the security of your application.

References