Skip to main content

Asymmetric denial of service - Content length

Need

Prevention of Content-Length manipulation in denial of service attacks

Context

  • Usage of Go 1.16 for developing high-performance and efficient applications
  • Usage of gin-gonic/gin for building web applications and APIs in Go
  • Usage of io/ioutil for reading and writing files in Node.js

Description

Non compliant code

package main

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

func main() {
r := gin.Default()
r.POST("/upload", func(c *gin.Context) {
_, _ = ioutil.ReadAll(c.Request.Body)
c.String(200, "upload complete")
})
r.Run()
}

The above Go code is an example of a simple web server using the Gin framework, which has a POST endpoint "/upload" that reads all the data from the request body. This is potentially vulnerable to asymmetric denial of service attacks due to the Content-Length field.

When a client sends a POST request to the "/upload" endpoint, it includes a Content-Length field in the header which specifies the size of the data that will be sent in the body of the request. The server reads this value and expects to receive that amount of data.

An attacker can exploit this by sending a very large value in the Content-Length field, but only send a small amount of data. The server will keep the connection open, waiting for the rest of the data to arrive. This can consume server resources and potentially lead to denial of service.

The vulnerability lies in the function ioutil.ReadAll(c.Request.Body), which attempts to read all data from the request body based on the Content-Length field. If the Content-Length field is spoofed to a very large value, this function could cause the server to wait indefinitely and consume excessive resources.

Steps

  • Implement input validation to check the Content-Length field in the request header.
  • Set a reasonable limit for the maximum allowed Content-Length value.
  • If the Content-Length value exceeds the limit, reject the request and return an appropriate error response.
  • Implement rate limiting or request throttling mechanisms to prevent excessive requests with high Content-Length values.
  • Consider implementing timeout mechanisms to close idle connections after a certain period of inactivity.
  • Regularly update and patch the Gin framework to ensure you have the latest security fixes.
  • Stay informed about new security vulnerabilities and best practices in web application security.

Compliant code

package main

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

const maxContentLength = 1024 * 1024 // 1MB

func main() {
r := gin.Default()
r.POST("/upload", func(c *gin.Context) {
contentLength, _ := strconv.Atoi(c.GetHeader("Content-Length"))
if contentLength > maxContentLength {
c.String(http.StatusRequestEntityTooLarge, "Request body too large")
return
}

_, _ = ioutil.ReadAll(c.Request.Body)
c.String(http.StatusOK, "upload complete")
})
r.Run()
}

The updated code includes a check for the Content-Length header in the request. If the Content-Length exceeds a predefined maximum value (in this case, 1MB), the server responds with a 413 Request Entity Too Large status code and does not process the request further.

This approach mitigates the risk of a denial of service attack by limiting the size of the request body that the server will accept. It also provides feedback to the client when the request body is too large, allowing the client to adjust the request and try again.

In addition to this, consider implementing rate limiting or request throttling mechanisms to prevent excessive requests with high Content-Length values. Also, consider implementing timeout mechanisms to close idle connections after a certain period of inactivity.

Regularly update and patch the Gin framework to ensure you have the latest security fixes. Stay informed about new security vulnerabilities and best practices in web application security.

References