Skip to main content

Insufficient data authenticity validation - Checksum verification

Need

Ensure proper data authenticity validation and checksum verification for resources loaded from external servers.

Context

  • Usage of TypeScript for statically typed JavaScript development
  • Usage of Express for building web applications and APIs
  • Usage of Axios for making HTTP requests

Description

Non compliant code

import express from 'express';
import axios from 'axios';

const app = express();

app.get('/external-resource', async (req, res) => {
const url = req.query.url;

try {
const response = await axios.get(url);
res.send(response.data);
} catch (error) {
res.status(500).send('Error fetching external resource');
}
});

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

The vulnerability in this code is an insufficient data authenticity validation, specifically the lack of checksum verification.

In the code, the application exposes an endpoint /external-resource that accepts a query parameter url which represents the URL of an external resource. The code then uses the axios library to make a GET request to the provided URL and sends the response data back to the client.

However, the code does not include any validation or verification of the integrity of the resource being fetched. This means that the application is using third-party resources without verifying that they have not been compromised or tampered with.

Without proper integrity validation, an attacker could potentially manipulate the response data from the external server, leading to various security risks. For example, an attacker could inject malicious code or deliver malicious files to the client, potentially leading to remote code execution, cross-site scripting (XSS) attacks, or the downloading of malware.

To address this vulnerability, it is recommended to implement checksum verification or other integrity validation mechanisms. This would involve calculating a checksum or hash of the received resource and comparing it with a trusted value to ensure that the data has not been tampered with.

Steps

  • Implement checksum verification for the external resource
  • Generate a checksum for the resource before downloading it
  • Compare the generated checksum with the received resource's checksum
  • If the checksums match, proceed with using the resource
  • If the checksums do not match, reject the resource and handle the error appropriately

Compliant code

import express from 'express';
import axios from 'axios';
import crypto from 'crypto';

const app = express();

app.get('/external-resource', async (req, res) => {
const url = req.query.url;

try {
const response = await axios.get(url);
const receivedData = response.data;
const receivedChecksum = response.headers['x-checksum'];

const generatedChecksum = crypto
.createHash('sha256')
.update(receivedData)
.digest('hex');

if (receivedChecksum === generatedChecksum) {
res.send(receivedData);
} else {
res.status(500).send('Checksum verification failed');
}
} catch (error) {
res.status(500).send('Error fetching external resource');
}
});

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

The fixed code addresses the vulnerability by implementing data authenticity validation through checksum verification. Here's an explanation of the changes made:

  1. The code imports the necessary modules: express for creating the server, axios for making HTTP requests, and crypto for generating checksums.

  2. The code creates an instance of the Express application.

  3. The code defines a route handler for the /external-resource endpoint using the app.get method. This endpoint expects a query parameter called url which represents the URL of the external resource.

  4. Inside the route handler, the code retrieves the url query parameter from the request.

  5. The code uses the axios library to make an HTTP GET request to the specified URL and awaits the response.

  6. The received data from the external server is stored in the receivedData variable, and the received checksum is extracted from the response headers and stored in the receivedChecksum variable.

  7. The code uses the crypto module to generate a checksum for the received data. It creates a SHA256 hash object, updates it with the received data, and then generates the checksum in hexadecimal format, which is stored in the generatedChecksum variable.

  8. The code compares the received checksum with the generated checksum using the === operator. If they match, it means that the integrity of the data has not been compromised.

  9. If the checksums match, the code sends the received data as the response to the client using res.send.

  10. If the checksums do not match, the code sends a 500 Internal Server Error response with the message "Checksum verification failed" using res.status(500).send.

  11. If there is an error while fetching the external resource, the code sends a 500 Internal Server Error response with the message "Error fetching external resource" using res.status(500).send.

  12. The code starts the server and listens on port 3000.

By performing checksum verification on the received data, the code ensures that the integrity of resources loaded from external servers is validated before using them.

References