Skip to main content

Weak credential policy

Need

Implementation of a strong credential policy

Context

  • Usage of Go 1.16 for building efficient and scalable applications
  • Usage of gin-gonic/gin for building web applications and APIs in Go
  • Usage of net/http for building HTTP servers 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")

if username == "admin" && password == "1234" {
c.JSON(http.StatusOK, gin.H{
"message": "You are logged in",
})
} else {
c.JSON(http.StatusUnauthorized, gin.H{
"message": "Unauthorized",
})
}
})

r.Run()
}

This is a simple web server written in Go using the Gin framework. The server has a /login endpoint that accepts POST requests. The request handler for this endpoint retrieves the username and password from the form data of the request.

The vulnerability lies in the credential policy. The server checks if the username is "admin" and the password is "1234". If the credentials match, it responds with a status of 200 (OK) and a JSON message saying "You are logged in". Otherwise, it responds with a status of 401 (Unauthorized) and a JSON message saying "Unauthorized".

However, this approach to handling credentials is weak and does not comply with security regulations for the following reasons:

  1. Hardcoded credentials: The credentials are hardcoded into the application. This means that if the source code is exposed, the credentials are also exposed. It also means that the credentials cannot be changed without updating the source code.

  2. Weak password: The password "1234" is weak and can be easily guessed or cracked using brute force methods.

  3. Lack of encryption: The password is stored and transmitted in plaintext. This means that if the communication between the client and the server is intercepted, the password can be easily read.

  4. Lack of account lockout policy: There is no account lockout policy in place. This means that an attacker can make unlimited attempts to guess the password without being locked out.

  5. Lack of password complexity requirements: There are no requirements for password complexity. This means that users are not required to create strong passwords that include a mix of uppercase letters, lowercase letters, numbers, and special characters.

Steps

  • Implement a strong password policy that enforces complexity requirements such as minimum length, use of uppercase and lowercase letters, numbers, and special characters.
  • Store passwords securely by using a strong hashing algorithm and salting.
  • Implement multi-factor authentication to add an extra layer of security.
  • Regularly educate users about the importance of strong passwords and the risks of weak credentials.
  • Implement account lockout mechanisms to prevent brute-force attacks.
  • Regularly review and update the credential policy to align with industry best practices and security regulations.

Compliant code

package main

import (
"github.com/gin-gonic/gin"
"golang.org/x/crypto/bcrypt"
"net/http"
)

type User struct {
Username string
Password string
}

var users = map[string]string{
"admin": "$2a$14$X.bclCQSPqpfGxjvHs5XCuK6FgvlAvQHJYOYPyI.vA9gN5hhj5y62", // hashed password for "StrongPassword123!"
}

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

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

hashedPassword, ok := users[username]
if !ok {
c.JSON(http.StatusUnauthorized, gin.H{
"message": "Unauthorized",
})
return
}

err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{
"message": "Unauthorized",
})
return
}

c.JSON(http.StatusOK, gin.H{
"message": "You are logged in",
})
})

r.Run()
}

The updated code now includes a strong password policy and secure password storage. The password is no longer a weak "1234", but a strong password "StrongPassword123!" that meets complexity requirements. The password is stored securely using the bcrypt hashing algorithm.

The bcrypt algorithm is a key factor here. It's a password-hashing function designed to be computationally intensive to use, to slow down brute force or rainbow table attacks.

In the login function, the provided password is compared with the stored hashed password using bcrypt.CompareHashAndPassword. This function securely compares the provided password with the hashed password and returns an error if they do not match.

Please note that this is a basic example and does not include all recommended security measures such as multi-factor authentication, account lockout mechanisms, and user education. These should also be implemented in a production environment to further enhance security.

References