Skip to main content

Insecure or unset HTTP headers - Accept

Need

Enforcement of secure and restricted HTTP headers for Accept

Context

  • Usage of TypeScript for statically typed JavaScript development
  • Usage of Express for building web applications and APIs

Description

Non compliant code

import express from 'express';

const app = express();

app.get('/api/data', (req, res) => {
const data = {
message: 'This is sensitive data',
secret: 'This is a secret',
};

res.json(data);
});

app.listen(3000, () => {
console.log('Server is running on port 3000');
});

The vulnerability in this code is that it does not set or validate the Accept header in the HTTP requests. The Accept header specifies the content types that the client is willing to accept in the response.

In this code, the server is responding with sensitive data in JSON format when a GET request is made to the '/api/data' endpoint. However, the server does not check or enforce any specific content type in the request. This means that the client can send a request without specifying the Accept header or with any arbitrary content type.

This vulnerability can be exploited by an attacker to cause unexpected behaviors in the application. For example, an attacker can send a request with an incorrect or unexpected content type, causing the server to misinterpret the data and potentially expose sensitive information.

To fix this vulnerability, the code should set the Accept header in the client requests and explicitly define the allowed content types for the application. Additionally, the server should deny any request that contains a content type different from the expected one.

Steps

  • Set the Accept header in the client requests to specify the expected content type.
  • Define explicitly the allowed content types for the application.
  • Deny all requests that contain a content type different from the expected by the application.

Compliant code

import express from 'express';

const app = express();

app.get('/api/data', (req, res) => {
const data = {
message: 'This is sensitive data',
secret: 'This is a secret',
};

res.json(data);
});

app.use((req, res, next) => {
const allowedContentTypes = ['application/json']; // Define the allowed content types

if (!req.headers.accept || !allowedContentTypes.includes(req.headers.accept)) {
res.status(406).send('Not Acceptable'); // Deny requests with unsupported content types
} else {
next();
}
});

app.listen(3000, () => {
console.log('Server is running on port 3000');
});

The fixed code addresses the vulnerability by implementing several measures to ensure the secure handling of HTTP headers.

First, the code defines an array called allowedContentTypes which explicitly lists the content types that the application will accept. In this case, it only allows the application/json content type.

Next, the code includes a middleware function that is executed for every incoming request. This middleware checks if the Accept header is present in the request and if it matches one of the allowed content types defined earlier. If the Accept header is missing or does not match any of the allowed content types, the middleware sends a response with a status code of 406 (Not Acceptable) and a corresponding message. This effectively denies any request that contains an unsupported content type.

If the Accept header is present and matches one of the allowed content types, the middleware calls the next() function to pass the control to the next middleware or route handler.

By implementing these measures, the fixed code ensures that only requests with the expected and allowed content types are processed, preventing any unexpected behaviors or misinterpretations of content types.

References