Skip to main content

Insecure deserialization

Need

Secure deserialization process

Context

  • Usage of TypeScript for type checking and static typing in Node.js development
  • Usage of Express for building web applications and APIs
  • Usage of body-parser for parsing request bodies in Express

Description

Non compliant code

import express from 'express';
import bodyParser from 'body-parser';

const app = express();
app.use(bodyParser.json());

app.post('/deserialize', (req, res) => {
const serializedObject = req.body;

// Insecure deserialization vulnerability
const deserializedObject = JSON.parse(serializedObject);

// Process the deserialized object
// ...

res.send('Deserialization complete');
});

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

The vulnerability in this code is an insecure deserialization vulnerability. It occurs in the app.post('/deserialize') route handler.

The code receives a serialized object in the request body and assigns it to the serializedObject variable. Then, it uses JSON.parse() to deserialize the object into the deserializedObject variable.

The problem with this approach is that it does not validate the content of the serialized object nor does it cast it to a specific type. This means that an attacker can potentially manipulate the serialized object to execute arbitrary code or control the application's execution flow.

By not validating the incoming serialized object, the code blindly trusts the content and assumes it is safe to deserialize. This can lead to various security issues, such as remote code execution or unauthorized access to sensitive data.

To fix this vulnerability, the code should implement proper validation of the serialized object before deserialization. This can include checking for expected properties, data types, or using a schema validation library to ensure the object's structure and content meet the expected criteria.

Steps

  • Validate the incoming serialized object to ensure it meets expected properties
  • Only deserialize the object if it passes the validation
  • Use a try-catch block to handle any potential errors during deserialization
  • Consider using a safer deserialization method or library
  • Implement additional security measures, such as input sanitization and whitelisting, to prevent malicious input

Compliant code

import express from 'express';
import bodyParser from 'body-parser';

const app = express();
app.use(bodyParser.json());

app.post('/deserialize', (req, res) => {
const serializedObject = req.body;

// Validate the incoming serialized object
if (typeof serializedObject === 'object' && serializedObject !== null) {
// Only deserialize the object if it passes the validation
try {
const deserializedObject = JSON.parse(serializedObject);

// Process the deserialized object
// ...

res.send('Deserialization complete');
} catch (error) {
// Handle any potential errors during deserialization
console.error('Error during deserialization:', error);
res.status(500).send('Error during deserialization');
}
} else {
res.status(400).send('Invalid serialized object');
}
});

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

The fixed code addresses the vulnerability by implementing proper validation and deserialization of incoming serialized objects.

  1. The code imports the necessary modules, including express for creating the server and body-parser for parsing the request body.

  2. The app variable is initialized as an instance of the Express application.

  3. The code uses the body-parser middleware to parse incoming JSON data.

  4. The app.post method defines a route for handling POST requests to the '/deserialize' endpoint.

  5. Inside the route handler, the serialized object is extracted from the request body using req.body.

  6. The code then performs validation on the serialized object. It checks if the object is of type 'object' and not null.

  7. If the serialized object passes the validation, the code attempts to deserialize it using JSON.parse(). This converts the serialized object into a JavaScript object.

  8. If the deserialization is successful, the code proceeds to process the deserialized object. This is where you can perform any necessary operations on the object.

  9. If any errors occur during deserialization, the code catches the error using a try-catch block. The error is logged to the console, and a 500 status code response is sent to the client indicating an error during deserialization.

  10. If the serialized object fails the validation, a 400 status code response is sent to the client indicating an invalid serialized object.

  11. The server listens on port 3000, and a message is logged to the console indicating that the server has started.

By validating the incoming serialized object and only deserializing it if it passes the validation, the code ensures that potentially malicious objects cannot control the application's execution flow.

References