logo

Non-encrypted confidential information - DB - Go


Need

Secure storage of confidential information in the database


Context

  1. Usage of Go 1.13 for building high-performance and scalable applications
  2. Usage of gin-gonic/gin for building web applications in Go
  3. Usage of gorm for Object-Relational Mapping (ORM) in Go programming
  4. Usage of GORM SQLite dialect for database operations

Description

Insecure Code Example

package main

import (
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
  _ "github.com/jinzhu/gorm/dialects/sqlite"
)

type User struct {
	gorm.Model
	Name     string
	Email    string `gorm:"type:varchar(100);unique_index"`
	Password string
}

var DB *gorm.DB

func main() {
	var err error
	DB, err = gorm.Open("sqlite3", "test.db")
	if err != nil {
		panic("failed to connect database")
	}
	defer DB.Close()
	DB.AutoMigrate(&User{})

	r := gin.Default()

	r.POST("/users", func(c *gin.Context) {
		name := c.PostForm("name")
		email := c.PostForm("email")
		password := c.PostForm("password")
		
		DB.Create(&User{Name: name, Email: email, Password: password})
		
		c.JSON(200, gin.H{
			"status": "user created",
		})
	})
	
	r.Run()
}

The above code represents a simple Go application using the Gin framework and GORM as an ORM for SQLite. The application has a `/users` endpoint that accepts POST requests to create a new user in the database. The vulnerability lies in the way the application handles user information. When a new user is created, the user's name, email, and password are stored directly in the database without any form of encryption. This means the data is stored in plain text, which is a major security risk. If an attacker gains access to the database, they can easily read all the stored user information. This could lead to unauthorized access to user accounts, identity theft, and other serious issues. The vulnerability could be fixed by adding encryption to the user data before storing it in the database. This would ensure that even if an attacker gains access to the database, they would not be able to read the user information without the encryption key.

Steps

  1. Use a secure connection to the database, such as HTTPS or SSL, to encrypt the data transmitted between the application and the database.
  2. Implement encryption for the confidential information stored in the database, such as the user's password.
  3. Use a secure hashing algorithm, like bcrypt, to hash the passwords before storing them in the database.
  4. Ensure that the database is properly configured with strong access controls and permissions to prevent unauthorized access.
  5. Regularly update and patch the database software to address any security vulnerabilities.
  6. Implement input validation and sanitization to prevent SQL injection attacks.
  7. Implement proper authentication and authorization mechanisms to control access to the confidential information in the database.
  8. Consider implementing additional security measures, such as two-factor authentication, to enhance the protection of the confidential information.

Secure Code Example

package main

import (
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
	"golang.org/x/crypto/bcrypt"
  _ "github.com/jinzhu/gorm/dialects/sqlite"
)

type User struct {
	gorm.Model
	Name     string
	Email    string `gorm:"type:varchar(100);unique_index"`
	Password string `gorm:"type:varchar(100);"`
}

var DB *gorm.DB

func main() {
	var err error
	DB, err = gorm.Open("sqlite3", "test.db")
	if err != nil {
		panic("failed to connect database")
	}
	defer DB.Close()
	DB.AutoMigrate(&User{})

	r := gin.Default()

	r.POST("/users", func(c *gin.Context) {
		name := c.PostForm("name")
		email := c.PostForm("email")
		password := c.PostForm("password")
		
		hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
		DB.Create(&User{Name: name, Email: email, Password: string(hashedPassword)})
		
		c.JSON(200, gin.H{
			"status": "user created",
		})
	})
	
	r.Run()
}

The updated code now includes the use of bcrypt, a secure hashing algorithm, to hash the passwords before storing them in the database. This is done by calling `bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)`. This function hashes the password using the bcrypt algorithm, with a cost of `bcrypt.DefaultCost`. The cost is a measure of how much computational power it would take to crack the hash, with higher costs being more secure but slower to compute. The hashed password is then stored in the database instead of the plain text password. This means that even if an attacker were able to gain access to the database, they would not be able to obtain the user's actual password. In addition to this, the `Password` field in the `User` struct has been updated to `gorm:"type:varchar(100);"` to ensure that the hashed password can be stored correctly. Please note that this code does not include all the recommended security measures such as secure connection to the database, proper access controls and permissions, input validation and sanitization, and two-factor authentication. These should be implemented as well to ensure the security of the confidential information in the database.


References

  • 246 - Non-encrypted confidential information - DB

  • Last updated

    2023/09/18