Business information leak - Customers or providers - Go

Business information leak - Customers or providers - Go

Need

Protection of sensitive business information from unauthorized access or leakage

Context

  • Usage of Go 1.16 for building efficient and scalable applications
  • Usage of Gin for building web applications in Go

Description

Non compliant code

        package main

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

type Customer struct {
	Name  string `json:"name"`
	Email string `json:"email"`
	Phone string `json:"phone"`
}

var Customers = []Customer{
	{"John Doe", "johndoe@example.com", "1234567890"},
	{"Jane Doe", "janedoe@example.com", "0987654321"},
}

func main() {
	r := gin.Default()
	r.GET("/customers", func(c *gin.Context) {
		c.JSON(200, Customers)
	})
	r.Run()
}
        
        

In the above code, we have a simple Gin application that serves customer data at the /customers endpoint. The customer data includes sensitive information such as name, email, and phone number.

The vulnerability lies in the /customers route handler. When a GET request is made to this endpoint, it responds with the entire list of customers, including their sensitive information. This means that anyone who can make a GET request to this endpoint can access this sensitive information.

This is a serious security issue as it can lead to information leakage. Attackers can exploit this vulnerability to gain unauthorized access to customer data, which can lead to a variety of problems including identity theft, spamming, and other forms of abuse.

Steps

  • Implement authentication and authorization mechanisms to restrict access to sensitive information.
  • Store sensitive information securely, such as using encryption or hashing algorithms.
  • Implement input validation and sanitization to prevent injection attacks.
  • Limit the amount of sensitive information exposed in API responses.
  • Implement rate limiting and throttling to prevent abuse and excessive data retrieval.
  • Regularly review and update access controls and permissions for sensitive data.
  • Implement logging and monitoring to detect and respond to any unauthorized access attempts.

Compliant code

        package main

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

type User struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

type Customer struct {
	Name  string `json:"-"`
	Email string `json:"email"`
	Phone string `json:"-"`
}

var Users = []User{
	{"admin", "$2a$10$7.0Zz8/0Z1S4yr1mZJKC.eC7akSq3HGjU2p3p8p6hIoLe6B6YUHmG"}, // password is "password"
}

var Customers = []Customer{
	{"John Doe", "johndoe@example.com", "1234567890"},
	{"Jane Doe", "janedoe@example.com", "0987654321"},
}

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

	store := cookie.NewStore([]byte("secret"))
	r.Use(sessions.Sessions("mysession", store))

	r.POST("/login", func(c *gin.Context) {
		var user User
		if err := c.ShouldBindJSON(&user); err == nil {
			for _, u := range Users {
				if user.Username == u.Username {
					err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(user.Password))
					if err == nil {
						session := sessions.Default(c)
						session.Set("user", user.Username)
						session.Save()
						c.JSON(200, gin.H{"message": "Logged in"})
						return
					}
				}
			}
		}
		c.JSON(401, gin.H{"message": "Authentication failed"})
	})

	r.GET("/customers", func(c *gin.Context) {
		session := sessions.Default(c)
		user := session.Get("user")
		if user == nil {
			c.JSON(401, gin.H{"message": "Unauthorized"})
			return
		}
		c.JSON(200, Customers)
	})

	r.Run()
}
        
        

The updated code includes several security measures to prevent unauthorized access to sensitive customer information.

1. Authentication: A new /login endpoint is added, which checks the provided username and password against a list of users. If the credentials match, a session is created for the user. The password is hashed using bcrypt, a secure hashing algorithm.

2. Authorization: The /customers endpoint now checks if a user is logged in before returning the customer data. If no user is logged in, it returns a 401 Unauthorized status.

3. Data Exposure: The json tags on the Customer struct have been updated to prevent the customer's name and phone number from being included in the JSON response. Only the email is included.

4. Session Management: The application now uses the sessions middleware from the gin-contrib/sessions package to manage user sessions. The session data is stored in a secure cookie.

Remember to replace "secret" with your own secret key in the cookie.NewStore([]byte("secret")) line. This key is used to sign the session cookie.

This code is a basic example and might need to be adjusted to fit your specific needs. For example, you might want to replace the hardcoded list of users with a database, or add rate limiting to prevent brute force attacks.

References