Skip to main content

Insecure session management - CSRF Fixation

Need

Secure session management and protection against CSRF Fixation

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('/transaction', (req, res) => {
const authorizationHeader = req.headers.authorization;
// Perform transaction logic
res.send('Transaction completed successfully');
});

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

The vulnerability in this code is an insecure session management issue known as CSRF (Cross-Site Request Forgery) Fixation.

In the code, the /transaction route is defined as a GET request handler. Inside the handler function, the code retrieves the authorization header from the request using req.headers.authorization.

The problem is that the authorization header is being used as a public key for authentication, and it is always the same for payment links. This means that an attacker can create a button or link that includes the content of a request and trick a user into clicking it. When the user clicks the button or link, the app will send a push notification to complete the transaction using the fixed authorization header.

This vulnerability allows an attacker to spoof an authenticated user in the application by modifying the link and executing critical transactions such as transfers or payments on behalf of the victim.

To fix this vulnerability, it is recommended to implement CSRF protection by using tokens in the forms for verification of requests made by legitimate users. This will ensure that only requests originating from the application itself are considered valid, preventing CSRF attacks.

Steps

  • Implement CSRF protection in the application
  • Generate and include a CSRF token in the forms used for transactions
  • Validate the CSRF token on the server-side before processing the transaction
  • Ensure that the CSRF token is unique for each session and request
  • Use a secure method to generate and store the CSRF token, such as using a cryptographic library or a secure random number generator
  • Include the CSRF token in the request headers or body when making a transaction request
  • Verify the CSRF token on the server-side by comparing it with the token stored in the session or database
  • Reject the transaction request if the CSRF token is invalid or missing
  • Regularly review and update the CSRF protection mechanism to address any new vulnerabilities or attack techniques

Compliant code

import express from 'express';
import csrf from 'csurf';

const app = express();
const csrfProtection = csrf({ cookie: true });

app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(csrfProtection);

app.get('/transaction', (req, res) => {
const authorizationHeader = req.headers.authorization;
// Perform transaction logic
res.send('Transaction completed successfully');
});

app.post('/transaction', (req, res) => {
const authorizationHeader = req.headers.authorization;
const csrfToken = req.csrfToken();
// Validate CSRF token
// Perform transaction logic
res.send('Transaction completed successfully');
});

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

The fixed code addresses the vulnerability by implementing CSRF protection using tokens. Here's an explanation of the changes made:

  1. The csrf middleware is imported from the csurf library. This middleware generates and validates CSRF tokens.

  2. The csrfProtection middleware is created using csrf({ cookie: true }). This configures the middleware to store the CSRF token in a cookie.

  3. The express.urlencoded and express.json middlewares are used to parse incoming request bodies.

  4. The csrfProtection middleware is added to the middleware stack using app.use(csrfProtection). This ensures that all routes below this middleware are protected against CSRF attacks.

  5. The GET /transaction route is modified to include the authorizationHeader in the request. This is just for demonstration purposes and should be replaced with the actual logic for handling transactions.

  6. The POST /transaction route is modified to include the authorizationHeader and csrfToken in the request. The csrfToken is obtained from req.csrfToken(), which generates a new CSRF token for each request.

  7. The POST /transaction route also includes a step to validate the CSRF token. This step ensures that the request is coming from a legitimate user and not from an attacker trying to perform a CSRF attack.

  8. After the necessary validations, the transaction logic is performed, and a response is sent back to the client.

  9. The server is set to listen on port 3000 using app.listen(3000).

References