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.