Skip to main content

Insecure or unset HTTP headers - Accept

Need

Enforcement of secure and appropriate HTTP headers - Accept

Context

  • Usage of Go 1.16 for building efficient and scalable applications
  • Usage of Gin framework for building web applications 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
}

In the above code, we have a basic Go backend application using the Gin framework. The application has a single route ("/") that responds with a string "Hello, World!" when a GET request is made.

The vulnerability lies in the fact that the application does not set the "Accept" HTTP header. The "Accept" header is used by HTTP clients to tell the server what content types they'll accept. The server will then send back a response, which will include a Content-Type header to tell the client what the content type of the returned content actually is.

In the provided code, any client can send a request without specifying an "Accept" header, or with an "Accept" header that allows any MIME type. If an attacker sends a request with an incorrect or malicious MIME type in the "Accept" header, the application might interpret the response content in a way that leads to unexpected behaviors or vulnerabilities.

This could be potentially exploited in a number of ways, depending on the specifics of the application and the data it handles. For instance, an attacker could attempt to trigger a content sniffing vulnerability in a user's browser, or to cause the application to process data in an unintended way.

Steps

  • Set the Accept header in the requests to a specific MIME type that the application expects.
  • Validate the Accept header in the server-side code to ensure that only the expected MIME types are accepted.
  • Reject requests with an invalid or unexpected Accept header and return an appropriate error response.
  • Implement content negotiation to handle requests with different Accept headers and return the appropriate response based on the requested MIME type.
  • Consider using a whitelist approach to specify the allowed MIME types instead of allowing any MIME type.
  • Regularly update and review the list of allowed MIME types to ensure it is up to date and secure.

Compliant code

package main

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

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

r.GET("/", func(c *gin.Context) {
accept := c.GetHeader("Accept")
if accept != "application/json" {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid Accept header"})
return
}
c.String(200, "Hello, World!")
})

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

The updated code now includes a check for the Accept header in the HTTP request. This is done using the GetHeader method from the gin context c. The Accept header is then compared to the expected MIME type, which in this case is application/json. If the Accept header does not match the expected MIME type, the server responds with a 400 Bad Request status and an error message indicating an invalid Accept header. If the Accept header is valid, the server proceeds to respond with the original message.

This fix addresses the vulnerability by ensuring that the server only accepts requests with the correct Accept header. This prevents an attacker from causing unexpected behaviors by sending requests with incorrect content-types. The server now also provides an appropriate error response when it receives a request with an invalid Accept header, which can help with debugging and error handling.

Remember to replace "application/json" with the actual MIME type that your application expects. If your application needs to accept multiple MIME types, you can implement a whitelist approach and check if the Accept header is in a list of allowed MIME types. Regularly review and update this list to ensure it is secure and up to date.

References