Non-encrypted confidential information - Credentials - Go
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
Insecure Code Example
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.
Secure Code Example
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: ```bash export ADMIN_USERNAME=admin export ADMIN_PASSWORD=admin123 ``` Remember to replace `admin` and `admin123` with your actual username and password.
References
Last updated
2023/09/18