Defending from Vulnerabilities: CSRF Bypass via Method Change

In the first week of the series, we delve into a specific CSRF (Cross-Site Request Forgery) attack scenario and understand how you could have identified and remediated while developing your application.

Defending from Vulnerabilities: CSRF Bypass via Method Change
Defending from Vulnerabilities

We are excited to announce our new blog series, "Defending from Vulnerabilities." As part of this series, we aim to publish a weekly attack-specific blog targeting how to defend against it, possible mitigations, and general best practices. This series aims to provide insights to pentesters, security engineers, developers, and bug bounty hunters.

In the first week of the series, we delve into a specific CSRF (Cross-Site Request Forgery) attack scenario and understand how you could have identified and remediated while developing your application.

Suppose your application has implemented CSRF tokens on POST requests to validate against CSRF attacks. The token validation works as expected, and removing the token results in a failed request. However, an attacker has found a way to bypass this protection by changing the method from POST to GET, removing the token, and successfully executing the request. This scenario highlights the importance of not only validating tokens but also ensuring the HTTP Method validation is properly enforced.

Understanding the Attack

Let's break down the attack, understanding the various components involved and their impact on its successful execution.

  1. CSRF Tokens and Their Role:
    • CSRF tokens are unique values generated for each session or request, embedded in forms, and validated on the server side to ensure the request is legitimate.
    • A CSRF token is typically validated in POST requests to prevent unauthorized actions by malicious websites.
  2. Attack Vector:
    • The attacker changes the request method from POST to GET.
    • Removes the CSRF token from the request.
    • The server processes the GET request without validating the CSRF token, allowing the attacker to perform unauthorized actions.

Defensive Strategy

Let's understand how to protect and secure your application against this attack, ensuring an attacker cannot exploit it.

To defend against this specific CSRF attack scenario, follow these steps:

1. Strict Method Enforcement:

To ensure that sensitive actions are only performed using the expected HTTP method (e.g., POST), you can implement middleware or filters that check the request method before processing the request. We are taking examples of two different programming languages, and you can consider implementing similar types of protections in your target language.

Express Example:

In an Express application, you can create middleware to enforce the HTTP method for specific routes.

const express = require('express');
const bodyParser = require('body-parser');
const app = express();

// Middleware to enforce POST method for /sensitive-action route
app.use((req, res, next) => {
  if (req.url === '/sensitive-action' && req.method !== 'POST') {
    return res.status(405).send('Method Not Allowed');
  }
  next();
});

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

app.post('/sensitive-action', (req, res) => {
  // Perform sensitive action
  res.send('Sensitive action performed successfully');
});

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

ASP.NET Core Example:

In an ASP.NET Core application, you can use attribute routing to enforce the HTTP method for specific actions.

using Microsoft.AspNetCore.Mvc;

public class SensitiveController : Controller
{
    [HttpPost]
    [ValidateAntiForgeryToken]
    public IActionResult SensitiveAction()
    {
        // Perform sensitive action
        return Ok("Sensitive action performed successfully");
    }

    [HttpGet]
    public IActionResult SensitiveAction()
    {
        return StatusCode(405, "Method Not Allowed");
    }
}

2. Token Validation Across Methods:

Ensure that CSRF tokens are validated for both POST and GET requests, or at least prevent GET requests from performing sensitive actions.

Express Example:

Using the csurf middleware, you can validate CSRF tokens for all requests and ensure sensitive actions only accept POST requests.

const express = require('express');
const csrf = require('csurf');
const bodyParser = require('body-parser');
const app = express();

const csrfProtection = csrf({ cookie: true });
app.use(bodyParser.urlencoded({ extended: false }));
app.use(csrfProtection);

app.post('/sensitive-action', (req, res) => {
  if (req.body._csrf !== req.csrfToken()) {
    return res.status(403).send('Invalid CSRF token');
  }
  // Perform sensitive action
  res.send('Sensitive action performed successfully');
});

app.get('/sensitive-action', (req, res) => {
  return res.status(405).send('Method Not Allowed');
});

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

ASP.NET Core Example:

Use the [ValidateAntiForgeryToken] attribute to enforce CSRF token validation for POST requests and handle other methods appropriately.

using Microsoft.AspNetCore.Mvc;

public class SensitiveController : Controller
{
    [HttpPost]
    [ValidateAntiForgeryToken]
    public IActionResult SensitiveAction()
    {
        // Perform sensitive action
        return Ok("Sensitive action performed successfully");
    }

    [HttpGet]
    public IActionResult SensitiveAction()
    {
        return StatusCode(405, "Method Not Allowed");
    }
}

3. Additional Recommendations:

  1. Secure Cookies:

Ensure your cookies are marked as HttpOnly and SameSite to protect the CSRF token.

Express Example:

const session = require('express-session');
app.use(session({
  secret: 'your_secret_key',
  resave: false,
  saveUninitialized: true,
  cookie: { httpOnly: true, sameSite: 'Strict' }
}));

ASP.NET Core Example:

services.ConfigureApplicationCookie(options =>
{
    options.Cookie.HttpOnly = true;
    options.Cookie.SameSite = SameSiteMode.Strict;
});
  1. Content Security Policy (CSP):

Implement CSP to restrict the sources that can execute scripts on your website.

Node.js/Express Example:

const helmet = require('helmet');
app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: ["'self'"],
    scriptSrc: ["'self'"]
  }
}));

ASP.NET Core Example:

services.AddCsp(options => options
    .DefaultSources(directive => directive.Self())
    .ScriptSources(directive => directive.Self()));

Conclusion

By implementing strict method validation, ensuring CSRF tokens are checked across all methods, and adopting additional security measures such as secure cookies and CSP, you can effectively defend against CSRF attacks in your application. This detailed approach helps developers and security engineers understand and apply these protections in specific scenarios.

In the comments, let us know if you find this blog useful and if you would like to learn about any specific attack vectors. We will try to include them in the upcoming series.

Stay tuned for more specific attack scenarios and defensive strategies in our weekly series. Make sure to subscribe to stay updated when the new series are published.