Skip to main content

Restricted fields manipulation

Need

Prevention of unauthorized access and manipulation of restricted fields

Context

  • Usage of Go 1.16 for developing high-performance and scalable applications
  • Usage of Gin framework for building web applications in Go
  • Usage of net/http for building HTTP servers in a Node.js application

Description

Non compliant code

package main

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

type Employee struct {
DNI string `json:"dni"`
Name string `json:"name"`
Email string `json:"email"`
BirthDate string `json:"birthdate"`
Address string `json:"address"`
PhoneNumber string `json:"phonenumber"`
}

var Employees = make(map[string]Employee)

func RegisterEmployee(c *gin.Context) {
var newEmployee Employee
if err := c.ShouldBindJSON(&newEmployee); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

Employees[newEmployee.DNI] = newEmployee

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

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

r.POST("/register", RegisterEmployee)

r.Run()
}

The above code is a simple HTTP server using the Gin framework in Go. It exposes a single endpoint /register that accepts a POST request with a JSON body representing an employee. The RegisterEmployee function is responsible for handling these requests.

The Employee struct is used to parse the incoming JSON body. It contains fields for various pieces of employee data, including DNI, name, email, birthdate, address, and phone number.

The RegisterEmployee function uses the ShouldBindJSON method provided by Gin to parse the incoming request body into an Employee struct. If the parsing is successful, the function then stores the new employee data in the Employees map, using the DNI as the key. If the DNI already exists in the map, the existing data will be overwritten with the new data.

This code is vulnerable because it allows any user to update the data of any employee by simply sending a POST request with the target employee's DNI. An attacker could potentially use this to change the information of employees from other companies, as described in the vulnerability context.

Steps

  • Implement authentication and authorization mechanisms to ensure that only authorized users can access and modify employee data.
  • Validate the input data to ensure that it is in the expected format and does not contain any malicious content.
  • Implement access control checks to ensure that users can only modify their own employee data.
  • Consider implementing a separate endpoint or mechanism for updating employee data to prevent unauthorized modifications.
  • Encrypt sensitive employee data, such as DNI, to protect it from unauthorized access or manipulation.
  • Regularly review and update the application to address any new security vulnerabilities or best practices.

Compliant code

package main

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

type Employee struct {
DNI string `json:"dni"`
Name string `json:"name"`
Email string `json:"email"`
BirthDate string `json:"birthdate"`
Address string `json:"address"`
PhoneNumber string `json:"phonenumber"`
}

var Employees = make(map[string]Employee)

func RegisterEmployee(c *gin.Context) {
var newEmployee Employee
if err := c.ShouldBindJSON(&newEmployee); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

// Check if the user is authenticated and authorized to make changes
user, _ := c.Get("user")
if user == nil || user.(string) != newEmployee.DNI {
c.JSON(http.StatusUnauthorized, gin.H{"error": "You are not authorized to make changes"})
return
}

Employees[newEmployee.DNI] = newEmployee

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

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

// Implement middleware for authentication
r.Use(AuthMiddleware())

r.POST("/register", RegisterEmployee)

r.Run()
}

func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// Implement your authentication logic here
// For example, check the Authorization header
token := c.GetHeader("Authorization")
if token == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
c.Abort()
return
}

// Validate the token and get the user's DNI
dni, err := validateToken(token)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
c.Abort()
return
}

// Set the user's DNI in the context
c.Set("user", dni)
c.Next()
}
}

func validateToken(token string) (string, error) {
// Implement your token validation logic here
// Return the user's DNI if the token is valid
return "", nil
}

The updated code includes an authentication middleware that checks if the user is authenticated before processing the request. This middleware is added to the Gin router with the Use function, so it will be executed for every request.

In the RegisterEmployee function, we now check if the user is authorized to make changes. We get the user's DNI from the context, which was set in the authentication middleware, and compare it with the DNI of the new employee. If they don't match, we return an unauthorized error.

The AuthMiddleware function is a Gin middleware that checks the Authorization header of the request. If the header is missing or the token is invalid, it returns an unauthorized error and aborts the request. If the token is valid, it sets the user's DNI in the context and continues with the next handler.

The validateToken function is a placeholder for your token validation logic. It should validate the token and return the user's DNI if the token is valid. If the token is invalid, it should return an error.

This way, we ensure that only authenticated and authorized users can register employees, and that they can only register employees with their own DNI. This prevents unauthorized users from manipulating the data of other employees.

References