Skip to main content

Insecure file upload

Need

Secure file upload and validation

Context

  • Usage of Go 1.16 for building efficient and scalable applications
  • Usage of gin-gonic/gin for building web applications in Go
  • Usage of net/http for handling HTTP requests and responses in a Node.js server
  • Usage of path/filepath for working with file paths and directories

Description

Non compliant code

package main

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

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

r.POST("/upload", func(c *gin.Context) {
file, _ := c.FormFile("file")
// Save the file without checking its extension or contents
c.SaveUploadedFile(file, filepath.Join("./uploads", file.Filename))
c.String(http.StatusOK, "File %s uploaded successfully", file.Filename)
})

r.Run(":8080")
}

The above code is a simple Go application using the Gin framework that allows for file uploads. The vulnerability lies within the "/upload" POST handler.

In this handler, the file is retrieved from the form data and saved directly to the server without any checks for the file's extension or content. This means that a user could upload a file with any extension, including potentially dangerous ones such as .html, .php, .exe, etc.

Furthermore, the lack of content validation means that these files could contain malicious code, which could lead to a variety of security issues depending on the server's configuration and the nature of the malicious code. For example, if the server is configured to execute .php files, a user could upload a .php file containing code that, when executed, could compromise the server.

This lack of validation and sanitization makes the system vulnerable to a variety of attack vectors, such as code injection or remote code execution attacks.

Steps

  • Implement file extension validation to only allow specific file types to be uploaded.
  • Use a secure file storage location instead of saving the files directly to the server.
  • Implement file content validation to check for malicious code or potential security threats.
  • Consider implementing file size restrictions to prevent large files from being uploaded.
  • Implement proper error handling and response messages for file upload failures.

Compliant code

package main

import (
"github.com/gin-gonic/gin"
"net/http"
"path/filepath"
"strings"
"errors"
)

const MaxUploadSize = 2 * 1024 * 1024 // 2 MB
var allowedExtensions = []string{".jpg", ".png", ".gif"}

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

r.POST("/upload", func(c *gin.Context) {
file, _ := c.FormFile("file")
err := validateFile(file)
if err != nil {
c.String(http.StatusBadRequest, "File upload failed: %s", err.Error())
return
}
// Save the file to a secure location
c.SaveUploadedFile(file, filepath.Join("./secure_uploads", file.Filename))
c.String(http.StatusOK, "File %s uploaded successfully", file.Filename)
})

r.Run(":8080")
}

func validateFile(file *gin.FormFile) error {
// Check file size
if file.Size > MaxUploadSize {
return errors.New("file size is too large")
}
// Check file extension
ext := strings.ToLower(filepath.Ext(file.Filename))
for _, allowedExt := range allowedExtensions {
if ext == allowedExt {
return nil
}
}
return errors.New("file type not allowed")
}

The updated code includes a function validateFile that checks the size and extension of the uploaded file. If the file is larger than 2 MB or its extension is not in the list of allowed extensions (".jpg", ".png", ".gif"), the function returns an error and the file is not saved.

The file is saved to a secure location ./secure_uploads instead of directly to the server.

The HTTP response status and message are also updated to reflect the success or failure of the file upload. If the file validation fails, the server responds with a 400 Bad Request status and a message indicating the reason for the failure. If the file is uploaded successfully, the server responds with a 200 OK status and a success message.

Please note that this code does not include file content validation for malicious code or potential security threats. This would require additional logic and possibly third-party libraries or services, depending on the specific requirements and threat model of your application.

References