External control of file name or path - Go

External control of file name or path - Go

Need

Prevention of unauthorized access and manipulation of file paths

Context

  • Usage of Go 1.16 for building high-performance and efficient applications
  • Usage of Gin for building web applications in Go
  • Usage of net/http for creating a web server in a Node.js application

Description

Non compliant code

        package main

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

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

	r.POST("/upload", func(c *gin.Context) {
		file, _ := c.FormFile("file")
		dst := c.PostForm("path")

		c.SaveUploadedFile(file, dst)

		c.String(http.StatusOK, "File %s uploaded successfully with fields path=%s.", file.Filename, dst)
	})
	r.Run()
}
        
        

The above code is a simple server application written in Go using the Gin framework. The server has a POST endpoint '/upload' which is designed to handle file uploads.

The vulnerability lies in the '/upload' endpoint. When a file is uploaded, the server saves the file to a destination path specified by the 'path' parameter in the POST request. This 'path' is directly taken from the user input without any sanitization or validation.

This is a serious security vulnerability because it allows an attacker to control the file path to which the uploaded file will be saved. An attacker could potentially overwrite any file on the system to which the server has write access. This could lead to unauthorized access, data corruption, or even code execution if the overwritten file is an executable or a configuration file.

Steps

  • Validate the 'path' parameter to ensure it is a safe and trusted location where the file should be saved.
  • Avoid using user-supplied input directly as the file path. Instead, generate a unique and secure file path using a secure algorithm or framework-provided functions.
  • Consider using a whitelist approach to restrict the allowed file paths to a predefined set of directories.
  • Implement proper file name validation to prevent any malicious or unexpected characters in the file name.
  • Set appropriate file permissions for the saved file to prevent unauthorized access.
  • Implement file type validation to ensure that only allowed file types are uploaded.
  • Implement rate limiting or file size restrictions to prevent abuse or denial-of-service attacks.
  • Regularly update and patch the underlying framework and libraries to benefit from security fixes and improvements.

Compliant code

        package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
	"path/filepath"
	"io/ioutil"
)

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

	r.POST("/upload", func(c *gin.Context) {
		file, _ := c.FormFile("file")
		// Generate a unique and secure file path using a secure algorithm
		dst := filepath.Join("/safe/path", filepath.Base(file.Filename))

		// Save the uploaded file to the generated path
		if err := c.SaveUploadedFile(file, dst); err != nil {
			c.String(http.StatusInternalServerError, "Failed to upload file: %s", err.Error())
			return
		}

		c.String(http.StatusOK, "File %s uploaded successfully with fields path=%s.", file.Filename, dst)
	})
	r.Run()
}
        
        

The updated code now ensures that the uploaded file is saved to a safe and trusted location, regardless of the 'path' parameter supplied by the user. This is achieved by generating a unique and secure file path using the filepath.Join and filepath.Base functions from the path/filepath package in Go.

The filepath.Join function is used to construct a file path that points to a predefined directory ( /safe/path in this case). The filepath.Base function is used to extract the base name of the file from the user-supplied file path, effectively discarding any directory information and preventing directory traversal attacks.

The c.SaveUploadedFile function is used to save the uploaded file to the generated path. If an error occurs during this operation, an HTTP 500 Internal Server Error response is returned to the client with a message indicating that the file upload failed.

The code then sends an HTTP 200 OK response to the client, indicating that the file was uploaded successfully. The response includes the original file name and the generated file path.

This approach effectively mitigates the risk of the 'External control of file name or path' vulnerability by ensuring that user-supplied input is not used directly to determine the file path, and by restricting the allowed file paths to a predefined set of directories.

References