Insecurely generated token - OTP - Go

Insecurely generated token - OTP - Go

Need

Secure generation and transmission of OTP tokens

Context

  • Usage of Go 1.16 for developing efficient and scalable applications
  • Usage of Gin framework for building web applications in Go
  • Usage of math/rand for generating random numbers
  • Usage of net/http for handling HTTP requests and responses in a Node.js server
  • Usage of strconv for string conversion and manipulation

Description

Non compliant code

        package main

import (
	"github.com/gin-gonic/gin"
	"math/rand"
	"net/http"
	"strconv"
)

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

	r.GET("/generateOTP", func(c *gin.Context) {
		otp := generateOTP()
		c.JSON(http.StatusOK, gin.H{
			"otp": otp,
		})
	})

	r.Run()
}

func generateOTP() string {
	return strconv.Itoa(rand.Intn(999999-100000) + 100000)
}
        
        

In the above code, we have a simple server created using the Gin framework in Go. There is an endpoint /generateOTP which generates a One-Time Password (OTP) when accessed. The generateOTP function is used to generate a random 6-digit OTP.

The vulnerability lies in the fact that the OTP is generated on the client-side and then sent to the server. This means that an attacker can simply intercept the request to access the OTP and continue the application flow without needing access to the phone number used.

This is a major security flaw as it allows for potential unauthorized access. The OTP is meant to be a secure method of authentication, but in this case, it can be easily bypassed.

To mitigate this vulnerability, the OTP should be generated server-side and then sent to the client. This way, even if an attacker intercepts the request, they will not have access to the OTP. Additionally, the OTP should be sent over a secure channel to prevent interception.

Steps

  • Generate the OTP server-side instead of client-side.
  • Use a secure random number generator to generate the OTP.
  • Ensure that the OTP is securely transmitted from the server to the client.
  • Implement additional security measures such as rate limiting and session management to prevent abuse of the OTP functionality.

Compliant code

        package main

import (
	"crypto/rand"
	"encoding/base64"
	"github.com/gin-gonic/gin"
	"net/http"
)

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

	r.GET("/generateOTP", func(c *gin.Context) {
		otp, err := generateOTP()
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{
				"error": "Failed to generate OTP",
			})
			return
		}

		c.JSON(http.StatusOK, gin.H{
			"otp": otp,
		})
	})

	r.Run()
}

func generateOTP() (string, error) {
	b := make([]byte, 32)
	_, err := rand.Read(b)
	if err != nil {
		return "", err
	}
	otp := base64.StdEncoding.EncodeToString(b)
	return otp, nil
}
        
        

The updated code now generates the OTP on the server-side, which is more secure than generating it on the client-side. The OTP is generated using a secure random number generator provided by the crypto/rand package. This ensures that the OTP is unpredictable and cannot be easily guessed by an attacker.

The OTP is then encoded using base64 encoding before being sent to the client. This ensures that the OTP is transmitted in a format that can be safely included in a JSON response.

In the event that an error occurs while generating the OTP, the server will respond with a 500 Internal Server Error status code and a JSON response containing an error message. This allows the client to handle the error appropriately.

Additional security measures such as rate limiting and session management should also be implemented to prevent abuse of the OTP functionality. For example, you could limit the number of OTPs that can be generated within a certain time period, or require the client to be authenticated before they can generate an OTP.

References