Non-encrypted confidential information - LDAP - Go

Non-encrypted confidential information - LDAP - Go

Need

Secure storage and transmission of LDAP service credentials

Context

  • Usage of Go 1.15 for building high-performance and scalable applications
  • Usage of gin-gonic/gin for building web applications in Go
  • Usage of gopkg.in/ldap.v2 for LDAP (Lightweight Directory Access Protocol) integration

Description

Non compliant code

        package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"gopkg.in/ldap.v2"
)

func main() {
	r := gin.Default()
	r.GET("/ldap", func(c *gin.Context) {
		l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
		if err != nil {
			c.JSON(500, gin.H{"error": "Unable to connect to LDAP server"})
			return
		}
		defer l.Close()

		err = l.Bind("cn=read-only-admin,dc=example,dc=com", "password")
		if err != nil {
			c.JSON(500, gin.H{"error": "Unable to bind to LDAP server"})
			return
		}

		c.JSON(200, gin.H{"message": "Successfully connected to LDAP server"})
	})

	r.Run(":8080")
}
        
        

The above code is a simple Go application using the Gin framework and the ldap.v2 package to connect to an LDAP server. The application exposes an endpoint /ldap which when hit, connects to an LDAP server, binds to it with a username and password, and sends a response to the client.

The vulnerability lies in the line:

                err = l.Bind("cn=read-only-admin,dc=example,dc=com", "password")

            


In this line, the username and password for the LDAP service are hardcoded directly into the application code in plain text. This is a significant security risk as anyone with access to the source code would be able to see these credentials. If these credentials have high privileges, an attacker could potentially use them to gain unauthorized access to sensitive data or systems.

Furthermore, if the source code is ever exposed (for example, if it is accidentally pushed to a public version control system), these credentials would be visible to anyone who views the code. This could potentially lead to a data breach.

In addition to the security risk, hardcoding credentials in the code also makes it difficult to change them. If the password needs to be updated, the code would need to be changed and the application would need to be redeployed. This is not a scalable or maintainable approach.

Steps

  • Remove the LDAP service credentials from the code.
  • Store the LDAP service credentials securely, such as in a configuration file or environment variables.
  • Encrypt the LDAP service credentials to ensure they are not exposed in plain text.
  • Update the code to retrieve the LDAP service credentials from the secure storage or environment variables.
  • Ensure that the secure storage or environment variables are properly protected and accessible only to authorized users.
  • Test the application to verify that it can connect to the LDAP server using the securely stored credentials.

Compliant code

        package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"gopkg.in/ldap.v2"
	"os"
)

func main() {
	r := gin.Default()
	r.GET("/ldap", func(c *gin.Context) {
		l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", os.Getenv("LDAP_HOST"), 389))
		if err != nil {
			c.JSON(500, gin.H{"error": "Unable to connect to LDAP server"})
			return
		}
		defer l.Close()

		err = l.Bind(os.Getenv("LDAP_BIND_DN"), os.Getenv("LDAP_PASSWORD"))
		if err != nil {
			c.JSON(500, gin.H{"error": "Unable to bind to LDAP server"})
			return
		}

		c.JSON(200, gin.H{"message": "Successfully connected to LDAP server"})
	})

	r.Run(":8080")
}
        
        

The original code had a vulnerability where the LDAP service credentials were exposed in plain text. This is a security risk as anyone with access to the code could see these credentials and potentially misuse them.

The updated code fixes this vulnerability by removing the hard-coded LDAP service credentials and instead retrieving them from environment variables. This is a more secure method of handling sensitive information such as credentials.

The os.Getenv function is used to retrieve the values of the LDAP_HOST, LDAP_BIND_DN, and LDAP_PASSWORD environment variables. These environment variables should be set in the environment where the application is running.

The LDAP_HOST environment variable should contain the host of the LDAP server. The LDAP_BIND_DN environment variable should contain the DN (Distinguished Name) to bind to the LDAP server. The LDAP_PASSWORD environment variable should contain the password to bind to the LDAP server.

By storing these credentials in environment variables, they are not exposed in the code and are only accessible to authorized users who have access to the environment where the application is running.

It's important to note that these environment variables should be protected and not exposed in any logs or error messages. They should also not be stored in the source code repository or any other place where they could be accessed by unauthorized users.

After updating the code, it's recommended to test the application to verify that it can still connect to the LDAP server using the credentials stored in the environment variables.

References