Skip to main content

Insecurely generated token - JWT

Need

Secure token generation for user creation service

Context

  • Usage of Go 1.15 for building high-performance and scalable applications
  • Usage of gin-gonic/gin for building web applications and APIs in Go
  • Usage of jwt-go for JSON Web Token (JWT) authentication and authorization

Description

Non compliant code

package main

import (
"github.com/gin-gonic/gin"
"github.com/dgrijalva/jwt-go"
"time"
)

var (
secretKey = "weakKey"
)

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

r.POST("/user", func(c *gin.Context) {
token := jwt.New(jwt.SigningMethodHS256)

claims := token.Claims.(jwt.MapClaims)
claims["name"] = "John Doe"
claims["admin"] = true
claims["exp"] = time.Now().Add(time.Hour * 24).Unix()

tokenString, _ := token.SignedString([]byte(secretKey))

c.JSON(200, gin.H{
"token": tokenString,
})
})
r.Run()
}

In the above code, we are using the Gin web framework to create a new user route. When a POST request is made to this route, a JSON Web Token (JWT) is created using the jwt-go package.

The token includes claims about the user such as their name and whether they are an admin. It also includes an expiration date, which is set to 24 hours from the current time.

The token is then signed using a secret key, which in this case is a weak and easily guessable string "weakKey". The signed token is returned in the response.

The problem here is that the use of a weak secret key makes the JWT vulnerable to attacks. An attacker could guess the secret key and use it to create their own tokens, or modify existing ones. This could allow them to impersonate other users, extend the expiration date of their own token, or even grant themselves admin privileges.

Steps

  • Generate a strong and secure secret key to sign the JWT tokens.
  • Store the secret key securely, such as in an environment variable or a secure configuration file.
  • Use a secure signing method, such as HMAC-SHA256 or RSA, to sign the JWT tokens.
  • Ensure that the expiration time of the token is set appropriately and cannot be easily manipulated by an attacker.
  • Consider using additional claims and validations to enhance the security of the JWT tokens.
  • Regularly review and update the secret key to maintain the security of the JWT tokens.

Compliant code

package main

import (
"github.com/gin-gonic/gin"
"github.com/dgrijalva/jwt-go"
"os"
"time"
)

var (
secretKey = os.Getenv("SECRET_KEY")
)

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

r.POST("/user", func(c *gin.Context) {
token := jwt.New(jwt.SigningMethodHS256)

claims := token.Claims.(jwt.MapClaims)
claims["name"] = "John Doe"
claims["admin"] = true
claims["exp"] = time.Now().Add(time.Hour * 24).Unix()

tokenString, _ := token.SignedString([]byte(secretKey))

c.JSON(200, gin.H{
"token": tokenString,
})
})
r.Run()
}

The updated code now securely generates JWT tokens. The secret key used to sign the tokens is now stored in an environment variable, which is a more secure method of storage than hardcoding the key into the application. This prevents the key from being easily discovered or leaked.

The JWT tokens are signed using HMAC-SHA256, a secure signing method. The expiration time of the tokens is set to 24 hours, which is a reasonable length of time that prevents tokens from being valid indefinitely if they are intercepted or stolen.

The claims in the token include the user's name and whether they are an admin. These claims can be used to control access to different parts of the application.

The secret key should be regularly reviewed and updated to maintain the security of the JWT tokens. This can be done by changing the value of the environment variable.

Remember to set the environment variable "SECRET_KEY" with a strong key before running the application.

References