XML injection (XXE) - TypeScript

XML injection (XXE) - TypeScript

Need

Prevention of XML injection attacks

Context

  • Usage of TypeScript for type-checking and compiling JavaScript code
  • Usage of Express for building web applications and APIs
  • Usage of body-parser for parsing request bodies in Express
  • Usage of xml2js for parsing XML data in JavaScript

Description

Non compliant code

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

const app = express();
app.use(bodyParser.text({ type: 'text/xml' }));

app.post('/parse-xml', (req, res) => {
  const xmlParser = new xml2js.Parser();
  xmlParser.parseString(req.body, (err, result) => {
    if (err) {
      res.status(400).send('Invalid XML format');
    } else {
      // Process the parsed XML data
      res.send('XML parsed successfully');
    }
  });
});

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

The vulnerability in the given code is XML injection, also known as XXE (XML External Entity) vulnerability.

In the code, the application uses the Express framework to create a server and handle HTTP requests. It also uses the bodyParser middleware with the 'text/xml' type to parse the request body as XML.

The vulnerability lies in the way the XML data is parsed using the xml2js library. The xml2js.Parser() function is used to parse the XML data received in the request body. However, this parser does not have any security measures in place to prevent XML injection attacks.

An attacker can exploit this vulnerability by sending specially crafted XML data in the request body. This XML code can contain external entities that are interpreted by the server, leading to various attacks. For example, the attacker can use external entities to read sensitive files from the server, perform remote code execution, or launch denial-of-service attacks.

To mitigate this vulnerability, it is recommended to implement proper input validation and filtering. One approach is to use a white-list approach, where only trusted XML elements and attributes are allowed. This can be done by implementing custom validation logic or by using a dedicated XML validation library that provides protection against XXE attacks.

Additionally, it is important to keep the software and libraries up to date to ensure that any security patches or fixes for XXE vulnerabilities are applied.

Steps

  • Implement input validation to filter the XML data received by the application.
  • Use a whitelist approach to only allow specific XML elements and attributes.
  • Sanitize the XML data before parsing it to remove any potentially malicious content.
  • Consider using a secure XML parsing library that provides protection against XXE attacks.
  • Regularly update the XML parsing library to ensure that any security vulnerabilities are patched.
  • Implement proper error handling to handle any parsing errors and prevent information leakage.
  • Consider implementing additional security measures such as rate limiting and authentication to protect against potential attacks.

Compliant code

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

const app = express();
app.use(bodyParser.text({ type: 'text/xml' }));

app.post('/parse-xml', (req, res) => {
  const xmlParser = new xml2js.Parser({
    explicitArray: false, // Prevents arrays for single elements
    mergeAttrs: true, // Merges attributes into the main object
    normalize: true, // Normalizes tag names
    normalizeTags: true, // Normalizes tag names
    trim: true, // Trims whitespace
    ignoreAttrs: true, // Ignores attributes
    explicitRoot: false, // Does not include root element in the result
    emptyTag: null, // Sets empty tags to null
    strict: true, // Throws an error if the XML is not well-formed
    validator: function (/* ... */) {
      // Implement your own XML validation logic here
    }
  });

  xmlParser.parseString(req.body, (err, result) => {
    if (err) {
      res.status(400).send('Invalid XML format');
    } else {
      // Process the parsed XML data
      res.send('XML parsed successfully');
    }
  });
});

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

The fixed code addresses the XML injection vulnerability by implementing several security measures:

1. The code uses the Express framework to handle HTTP requests and responses.

2. The body-parser middleware is used to parse the request body as text with the specified content type of text/xml. This ensures that the server expects XML data in the request.

3. The xml2js library is used to parse the XML data received from the request body. The Parser object is configured with various options to ensure secure parsing of the XML.

4. The explicitArray option is set to false to prevent the creation of arrays for single elements. This helps to avoid potential vulnerabilities related to array manipulation.

5. The mergeAttrs option is set to true to merge attributes into the main object. This helps to simplify the resulting parsed XML data structure.

6. The normalize and normalizeTags options are set to true to normalize tag names. This ensures consistency in the parsed XML data and helps prevent potential vulnerabilities related to case sensitivity or variations in tag names.

7. The trim option is set to true to remove leading and trailing whitespace from tag values. This helps to prevent potential vulnerabilities related to whitespace manipulation.

8. The ignoreAttrs option is set to true to ignore attributes in the parsed XML data. This reduces the complexity of the resulting data structure and helps prevent potential vulnerabilities related to attribute manipulation.

9. The explicitRoot option is set to false to exclude the root element from the parsed XML data. This simplifies the resulting data structure and helps prevent potential vulnerabilities related to root element manipulation.

10. The emptyTag option is set to null to treat empty tags as null values. This helps to prevent potential vulnerabilities related to empty tag manipulation.

11. The strict option is set to true to throw an error if the XML is not well-formed. This helps to ensure that only valid XML data is processed.

12. The validator option is left empty in the code, but it provides a placeholder for implementing custom XML validation logic. This allows developers to add additional validation checks if required.

13. If an error occurs during XML parsing, the server responds with a 400 Bad Request status and sends an error message indicating that the XML format is invalid.

14. If the XML parsing is successful, the server responds with a success message indicating that the XML was parsed successfully.

15. The server listens on port 3000 for incoming requests.

Overall, the fixed code implements secure XML parsing by configuring the xml2js library with various options that help prevent XML injection vulnerabilities.

References