Skip to main content

Lack of data validation - Dates

Need

Implementation of robust data validation for date fields

Context

  • Usage of Go 1.16 for building efficient and scalable applications
  • Usage of gin-gonic/gin for building web applications in Go

Description

Non compliant code

package main

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

type User struct {
Name string `json:"name"`
Email string `json:"email"`
BirthDate time.Time `json:"birth_date"`
}

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

r.PUT("/user/:id", func(c *gin.Context) {
var user User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}

// Update user in database here

c.JSON(200, gin.H{"status": "User updated"})
})

r.Run() // listen and serve on 0.0.0.0:8080
}

The above code is a simple implementation of a PUT endpoint in a Go application using the Gin framework. This endpoint is used to update a user's details. The user details are received in the request body as JSON.

The vulnerability lies in the lack of data validation. The code does not check if the BirthDate field in the request is a valid date. It simply binds the incoming JSON to the User struct without any validation. This means that a client can send a request with an invalid date in the BirthDate field, and the server will accept it and try to process it, potentially leading to unexpected behavior or errors.

Furthermore, the code does not check if the client has the permission to modify the user's details. This means that any client can send a PUT request to update any user's details, which is a serious security issue.

This lack of server-side validation and control can be exploited by an attacker to manipulate user data in unauthorized ways.

Steps

  • Implement server-side validation for the birth_date field in the User struct.
  • Validate the birth_date field to ensure it is a valid date format.
  • Check if the user has permission to modify the birth_date field before updating it in the database.
  • Return an appropriate error response if the birth_date field is invalid or the user does not have permission to modify it.

Compliant code

package main

import (
"github.com/gin-gonic/gin"
"time"
"net/http"
)

type User struct {
Name string `json:"name"`
Email string `json:"email"`
BirthDate time.Time `json:"birth_date"`
}

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

r.PUT("/user/:id", func(c *gin.Context) {
var user User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

// Validate birth_date
if user.BirthDate.IsZero() {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid birth date"})
return
}

// Check user permission here
// If the user does not have permission to modify the birth_date field, return an error
// ...

// Update user in database here

c.JSON(http.StatusOK, gin.H{"status": "User updated"})
})

r.Run() // listen and serve on 0.0.0.0:8080
}

The updated code now includes server-side validation for the birth_date field in the User struct. This is done by checking if the BirthDate field is a zero value, which in Go signifies that the field is not set. If the BirthDate field is a zero value, the server responds with a 400 Bad Request status and an error message indicating that the birth date is invalid.

Additionally, before updating the user in the database, the server should check if the user has permission to modify the birth_date field. This is represented by a comment in the code and should be replaced with the actual permission checking logic.

If the user does not have permission to modify the birth_date field, the server should respond with an appropriate error message and status code.

By implementing these checks, the server can prevent unauthorized modifications to the birth_date field and ensure that only valid dates are accepted.

References