Lack of protection against brute force attacks - Credentials - Go

Lack of protection against brute force attacks - Credentials - Go

Need

Implementation of strong authentication mechanisms to prevent brute force attacks on promotional codes.

Context

  • Usage of Go 1.16 for building high-performance and scalable applications
  • Usage of Gin framework for building web applications in Go

Description

Non compliant code

        package main

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

type PromoCode struct {
	Code string `json:"code"`
}

var validCodes = []string{"PROMO1", "PROMO2", "PROMO3"}

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

	r.POST("/validate-promo", func(c *gin.Context) {
		var promo PromoCode
		if err := c.ShouldBindJSON(&promo); err != nil {
			c.JSON(400, gin.H{"error": err.Error()})
			return
		}

		for _, validCode := range validCodes {
			if promo.Code == validCode {
				c.JSON(200, gin.H{"status": "Promo code is valid"})
				return
			}
		}

		c.JSON(400, gin.H{"status": "Invalid promo code"})
	})
	r.Run()
}
        
        

This Go code snippet is a simple web server using the Gin framework. It exposes a POST endpoint /validate-promo that accepts a JSON object containing a promotional code and checks if the code is valid.

The vulnerability lies in the fact that there is no protection against brute force attacks. An attacker could potentially send many requests with different promotional codes until they find a valid one. This is because the server does not implement any mechanism to limit the number of requests per IP address, does not use CAPTCHA to ensure the client is not a bot, and does not implement any delay mechanism after a certain number of failed attempts.

The for loop iterates over the validCodes slice to check if the provided promo code matches one of the valid ones. If a match is found, it returns a 200 status with a message saying the promo code is valid. If no match is found after checking all the valid codes, it returns a 400 status with a message saying the promo code is invalid.

The lack of protection against brute force attacks makes this code vulnerable to automated guessing of promotional codes.

Steps

  • Implement rate limiting to limit the number of requests from a single IP address within a certain time frame.
  • Implement account lockout mechanism to temporarily lock user accounts after a certain number of failed login attempts.
  • Use strong and complex passwords for user accounts to make it harder for brute force attacks to guess the credentials.
  • Implement CAPTCHA or reCAPTCHA to differentiate between human and automated requests.
  • Implement multi-factor authentication (MFA) to add an extra layer of security to the authentication process.
  • Implement a delay or sleep mechanism after each failed login attempt to slow down automated brute force attacks.
  • Monitor and log failed login attempts to detect and respond to potential brute force attacks.
  • Regularly update and patch the application and its dependencies to fix any known vulnerabilities that could be exploited in brute force attacks.
  • Educate users about the importance of using strong passwords and avoiding password reuse to protect against brute force attacks.

Compliant code

        package main

import (
	"github.com/gin-contrib/limiter"
	"github.com/gin-gonic/gin"
	"time"
)

type PromoCode struct {
	Code string `json:"code"`
}

var validCodes = []string{"PROMO1", "PROMO2", "PROMO3"}

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

	// Implement rate limiting
	rateLimiter := limiter.NewRateLimiter(time.Minute, 5, func(c *gin.Context) string {
		// limit rate by IP
		return c.ClientIP()
	})

	r.Use(rateLimiter.Middleware())

	r.POST("/validate-promo", func(c *gin.Context) {
		var promo PromoCode
		if err := c.ShouldBindJSON(&promo); err != nil {
			c.JSON(400, gin.H{"error": err.Error()})
			return
		}

		for _, validCode := range validCodes {
			if promo.Code == validCode {
				c.JSON(200, gin.H{"status": "Promo code is valid"})
				return
			}
		}

		c.JSON(400, gin.H{"status": "Invalid promo code"})
	})
	r.Run()
}
        
        

The updated code now includes a rate limiter middleware that limits the number of requests from a single IP address to 5 per minute. This is done using the limiter package from gin-contrib.

The rate limiter is created with a time window of one minute and a maximum of 5 requests. The key for the rate limiter is the client's IP address, which is obtained from the context of the request.

The rate limiter middleware is then added to the Gin engine using the Use function. This ensures that the rate limiter is applied to all incoming requests.

In the /validate-promo route, the application checks if the promo code provided in the request is valid. If it is, a success message is returned. If it's not, an error message is returned.

This update significantly reduces the risk of brute force attacks by limiting the number of requests an attacker can make within a certain time frame. However, it's important to note that this is just one layer of defense and additional security measures such as CAPTCHA, account lockouts, and strong passwords should also be implemented to further protect against brute force attacks.

References