Skip to main content

Non-encrypted confidential information - Credentials

Need

Secure storage and transmission of confidential information

Context

  • Usage of Go 1.16 for building efficient 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"
)

var username = "admin"
var password = "admin123"

func main() {
r := gin.Default()
r.GET("/admin", func(c *gin.Context) {
c.JSON(200, gin.H{
"username": username,
"password": password,
})
})
r.Run()
}

This code is a simple Go application using the Gin framework. It defines a route /admin that returns the username and password in plain text when accessed.

The main vulnerability here is that the username and password are hardcoded into the source code in plain text. This is a major security flaw as anyone who has access to the source code can easily see the credentials.

Moreover, these credentials are returned as a JSON response when the /admin route is accessed. This is a bad practice as it exposes sensitive data over the network, which could be intercepted by attackers.

In a real-world application, credentials should never be hardcoded into the source code and they should certainly never be transmitted over the network in plain text.

Steps

  • Store passwords securely using a strong hashing algorithm.
  • Do not hardcode passwords in the source code.
  • Use environment variables or a configuration file to store sensitive information.
  • Encrypt the sensitive information before storing it.
  • Implement secure authentication mechanisms such as OAuth or JWT.
  • Implement secure password reset and recovery processes.
  • Regularly update and patch the application and its dependencies.
  • Perform regular security audits and penetration testing.
  • Educate developers about secure coding practices and the importance of protecting sensitive information.

Compliant code

package main

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

func main() {
r := gin.Default()
r.GET("/admin", func(c *gin.Context) {
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(os.Getenv("ADMIN_PASSWORD")), bcrypt.DefaultCost)
c.JSON(200, gin.H{
"username": os.Getenv("ADMIN_USERNAME"),
"password": string(hashedPassword),
})
})
r.Run()
}

The updated code now uses environment variables to store the username and password. This prevents the sensitive information from being hardcoded into the source code, which is a security risk.

The password is hashed using the bcrypt hashing algorithm before it is stored. This means that even if an attacker is able to access the password, they will not be able to use it without first cracking the hash. Bcrypt is a strong, slow hashing algorithm that is resistant to brute force and rainbow table attacks.

The bcrypt.GenerateFromPassword function is used to hash the password. The bcrypt.DefaultCost parameter determines the computational cost of the hash, with higher values being slower but more secure.

The hashed password is then converted to a string and stored in the password variable. This variable is then returned in the JSON response.

Please note that you need to set the environment variables ADMIN_USERNAME and ADMIN_PASSWORD before running the application. You can do this in the terminal with the export command:

export ADMIN_USERNAME=admin
export ADMIN_PASSWORD=admin123

Remember to replace admin and admin123 with your actual username and password.

References