Insecure or unset HTTP headers - X-Content-Type-Options - Go

Insecure or unset HTTP headers - X-Content-Type-Options - Go

Need

Enforce secure content type handling

Context

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

Description

Non compliant code

        package main

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

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

	r.GET("/", func(c *gin.Context) {
		c.String(200, "Hello, World!")
	})

	r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
        
        

In the above code, we have a simple web server using the Gin framework in Go. The server listens on port 8080 and responds to GET requests on the root ("/") endpoint with a "Hello, World!" message.

However, this code is vulnerable because it does not set the X-Content-Type-Options HTTP header. This header is used to protect against MIME type confusion attacks. By not setting this header to 'nosniff', the server allows the browser to interpret the content type, which can lead to security vulnerabilities.

For example, if an attacker can trick a user into uploading a file with a malicious script but with an image extension (like .jpg or .png), the browser might interpret it as an executable script and run it, leading to a Cross-Site Scripting (XSS) attack.

By setting the X-Content-Type-Options to 'nosniff', the server instructs the browser to not interpret the content type, and thus, prevents such attacks.

Steps

  • Add the X-Content-Type-Options header to the server's response.
  • Set the value of the X-Content-Type-Options header to 'nosniff'.
  • Ensure that the X-Content-Type-Options header is set for all responses, including error responses.
  • Verify that the X-Content-Type-Options header is correctly set by inspecting the server's response headers.

Compliant code

        package main

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

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

	r.Use(func(c *gin.Context) {
		c.Header("X-Content-Type-Options", "nosniff")
		c.Next()
	})

	r.GET("/", func(c *gin.Context) {
		c.String(200, "Hello, World!")
	})

	r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
        
        

The above code fixes the vulnerability by adding a middleware function that sets the X-Content-Type-Options header to nosniff for all responses. This header is a security feature that helps prevent attacks based on MIME-type confusion. Setting this header to nosniff instructs the browser to not try to interpret content differently from the declared content type.

The middleware function is added using the Use function of the gin router. This function takes a handler function that will be executed for every request that the router receives. In the handler function, we use the Header function of the gin context to set the X-Content-Type-Options header. After setting the header, we call the Next function of the gin context to pass control to the next middleware function or the final handler function.

This middleware function will be executed for all requests, including error responses, ensuring that the X-Content-Type-Options header is always set.

References