Insecure or unset HTTP headers - X-Frame Options - TypeScript

Insecure or unset HTTP headers - X-Frame Options - TypeScript

Need

Implementation of secure and properly configured HTTP headers

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('/', (req, res) => {
  res.setHeader('X-Frame-Options', 'ALLOW-FROM https://malicious-website.com');
  res.send('Hello World!');
});

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

The vulnerability in the provided TypeScript code is related to the insecure or unset HTTP header, specifically the X-Frame-Options header.

In the code, the X-Frame-Options header is set to allow framing from a specific domain, 'https://malicious-website.com'. This header is intended to protect against clickjacking attacks by specifying which domains are allowed to embed the application in an iframe. However, in this case, the header is set to allow framing from a potentially malicious website.

This vulnerability can be exploited by an attacker who controls the malicious-website.com domain. They can embed the application in an iframe on their website and potentially trick users into performing unintended actions or disclosing sensitive information.

To mitigate this vulnerability, it is recommended to disable the X-Frame-Options header from the server responses. Additionally, it is advised to define the frame_ancestors policy in the Content Security Policy (CSP) header. The frame_ancestors policy allows you to specify which domains are allowed to embed the application in an iframe, providing a more secure alternative to the deprecated X-Frame-Options header.

Steps

  • Remove the line that sets the X-Frame-Options header in the server response
  • Add the Content-Security-Policy header with the frame-ancestors directive to specify the allowed frame ancestors
  • Set the frame-ancestors directive to 'none' if the application should not be embedded in any frames, or specify the allowed origins if the application should be embedded in specific frames

Compliant code

        import express from 'express';

const app = express();

app.use((req, res, next) => {
  res.setHeader('Content-Security-Policy', "frame-ancestors 'none'");
  next();
});

app.get('/', (req, res) => {
  res.send('Hello World!');
});

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

The fixed code is written in TypeScript using the Express framework. It addresses the vulnerability related to insecure or unset HTTP headers by implementing the Content Security Policy (CSP) header with the frame-ancestors policy.

In the code, we import the Express module and create an instance of the application using the express() function.

The app.use() middleware function is used to set the Content-Security-Policy header on all server responses. The value of the header is set to frame-ancestors 'none', which means that the application should not be embedded in any frames or iframes.

The app.get() function defines a route for the root URL ("/") and sends the response "Hello World!".

Finally, the app.listen() function starts the server on port 3000 and logs a message to the console.

By setting the Content-Security-Policy header with the frame-ancestors policy to 'none', the fixed code ensures that the application cannot be embedded in any frames, thereby preventing clickjacking attacks.

References