Skip to main content

Cross-site request forgery

Need

Protection against cross-site request forgery 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 applications

Description

Non compliant code

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

const app = express();
app.use(bodyParser.urlencoded({ extended: false }));

app.get('/transfer', (req, res) => {
res.send(`
<form action="/transfer" method="POST">
<input type="hidden" name="amount" value="1000">
<input type="hidden" name="to" value="attacker">
<button type="submit">Transfer</button>
</form>
`);
});

app.post('/transfer', (req, res) => {
const amount = req.body.amount;
const to = req.body.to;

// Transfer the amount to the specified account
// This code is vulnerable to CSRF attack

res.send(`Transfer successful!`);
});

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

The vulnerability in the provided code is Cross-Site Request Forgery (CSRF).

In the code, there is a route defined for transferring funds (/transfer). The GET request to this route renders a form with hidden input fields for the amount and recipient. The form is then submitted via a POST request to the same /transfer route.

The issue is that there is no mechanism in place to prevent CSRF attacks. An attacker can create a malicious website and trick an authenticated user into visiting it. When the user visits the malicious website, the attacker's code can automatically submit the form on behalf of the user without their consent. This means that the user's funds can be transferred to the attacker's account without their knowledge.

To fix this vulnerability, the application should implement CSRF protection by using tokens in forms. These tokens should be generated and included in the form as a hidden input field. When the form is submitted, the server should validate the token to ensure that the request is coming from a legitimate source. This prevents attackers from forging requests and protects users from unauthorized actions.

Steps

  • Generate a CSRF token and include it in the form
  • Validate the CSRF token on the server-side
  • Reject requests without a valid CSRF token

Compliant code

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

const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(csurf());

app.get('/transfer', (req, res) => {
const csrfToken = req.csrfToken();

res.send(`
<form action="/transfer" method="POST">
<input type="hidden" name="_csrf" value="${csrfToken}">
<input type="hidden" name="amount" value="1000">
<input type="hidden" name="to" value="attacker">
<button type="submit">Transfer</button>
</form>
`);
});

app.post('/transfer', (req, res) => {
const amount = req.body.amount;
const to = req.body.to;

// Transfer the amount to the specified account
// This code is vulnerable to CSRF attack

res.send(`Transfer successful!`);
});

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

In the fixed code, several measures have been implemented to prevent cross-site request forgery (CSRF) attacks.

  1. The csurf middleware is used to generate and validate CSRF tokens. It is added as a middleware using app.use(csurf()). This middleware automatically generates a CSRF token and attaches it to the request object.

  2. In the GET route handler for /transfer, the generated CSRF token is retrieved using req.csrfToken(). This token is then included as a hidden input field in the form.

  3. In the POST route handler for /transfer, the CSRF token is automatically validated by the csurf middleware. If the token is missing or invalid, an error will be thrown.

By including the CSRF token in the form and validating it in the POST route handler, the fixed code ensures that only requests with a valid token can be processed. This prevents attackers from tricking authenticated users into executing actions without their consent.

References