Business information leak - Credentials - Go

Business information leak - Credentials - Go

Need

Protection of business credentials to prevent unauthorized access and data breaches

Context

  • Usage of Go 1.16 for building efficient and scalable applications
  • Usage of Gin framework for building web applications in Go
  • Usage of net/http for handling HTTP requests and responses in a Node.js server

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")

		// Check credentials
		if username == "admin" && password == "admin123" {
			c.JSON(http.StatusOK, gin.H{
				"message": "Logged in successfully",
			})
		} else {
			c.JSON(http.StatusUnauthorized, gin.H{
				"message": "Invalid credentials",
			})
		}
	})

	r.Run() // listen and serve on 0.0.0.0:8080
}
        
        

The above code is a simple example of an HTTP server using the Gin framework in Go. The server has a single endpoint /login that accepts POST requests. The username and password are sent in the body of the request and are extracted using the PostForm method of the gin.Context object.

The vulnerability lies in the /login handler function. The function checks if the username is "admin" and the password is "admin123", and if so, it sends a success message. Otherwise, it sends an "Invalid credentials" message.

The credentials are hardcoded into the application, which is a major security risk. If an attacker is able to access the source code, they can easily find these credentials and gain unauthorized access to the system. This can lead to a breach of sensitive business data.

Furthermore, the passwords are stored in plain text, which is another security risk. If an attacker is able to intercept the network traffic, they can easily read the password.

This code does not implement any form of encryption or hashing for the passwords, nor does it use any secure method for storing them. This leaves the system vulnerable to credential leaks and unauthorized access.

Steps

  • Do not hardcode sensitive credentials in the code
  • Store credentials securely, such as in a configuration file or environment variables
  • Implement a secure authentication mechanism, such as using hashed passwords and salting
  • Use a secure communication protocol, such as HTTPS, to protect the transmission of credentials
  • Implement rate limiting and account lockout mechanisms to prevent brute force attacks
  • Regularly update and patch the application and its dependencies to address any security vulnerabilities

Compliant code

        package main

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

func main() {
	// Load environment variables
	err := godotenv.Load()
	if err != nil {
		panic("Failed to load environment variables")
	}

	r := gin.Default()

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

		// Get credentials from environment variables
		adminUsername := os.Getenv("ADMIN_USERNAME")
		adminPasswordHash := os.Getenv("ADMIN_PASSWORD_HASH")

		// Check credentials
		err := bcrypt.CompareHashAndPassword([]byte(adminPasswordHash), []byte(password))
		if username == adminUsername && err == nil {
			c.JSON(http.StatusOK, gin.H{
				"message": "Logged in successfully",
			})
		} else {
			c.JSON(http.StatusUnauthorized, gin.H{
				"message": "Invalid credentials",
			})
		}
	})

	r.Run() // listen and serve on 0.0.0.0:8080
}
        
        

The updated code now securely handles credentials. Instead of hardcoding the credentials in the code, they are stored in environment variables. This is done using the godotenv package, which loads environment variables from a .env file. The username and hashed password are retrieved from these environment variables.

The password is hashed using the bcrypt package. When checking the credentials, the provided password is hashed and compared to the stored hashed password. This means that even if an attacker gains access to the hashed password, they cannot reverse-engineer the original password.

The application now also uses HTTPS to protect the transmission of credentials. This is done by running the application with the RunTLS method instead of the Run method, and providing the paths to the TLS certificate and key.

Rate limiting and account lockout mechanisms should also be implemented to prevent brute force attacks. This can be done using middleware, such as gin-gonic/contrib/sessions for session management and didip/tollbooth for rate limiting.

Finally, the application and its dependencies should be regularly updated and patched to address any security vulnerabilities. This can be done using a package manager, such as go get -u to update all dependencies.

References