Skip to content

Cross Site Request Forgery (CSRF)

What does this mean ?

Cross-Site Request Forgery (CSRF) is an attack that compels an authorized end user to do undesirable activities on a web application. An attacker can deceive users of a web application into performing activities of the attacker's choosing with the use of social engineering (such as delivering a link through email or chat). If the target is a regular user, a successful CSRF attack can force the user to conduct state-changing actions such as transferring payments or changing their email address. CSRF can compromise the entire web application if the victim is an administrative account.

What can happen ?

In a successful CSRF attack, the attacker induces the target user to do an accidental action. This might be to update their email address, reset their password, or initiate a money transfer, for example. The attacker may be able to obtain complete control of the user's account depending on the nature of the activity. If the compromised user has a privileged position inside the program, the attacker may be able to gain complete control of all data and functionality.

Recommendation

The most effective technique to prevent CSRF attacks is to include a CSRF token in relevant queries. The token should be as follows:

  • Unpredictable with large entropy, which is the case with session tokens in general.
  • Connected to the user's session.
  • Every case is rigorously evaluated before the required action is carried out.

Sample Code

Vulnerable :

public class TestController
{
    [HttpPost]
    public ActionResult ControllerMethod(string input)
    {
        //Do an action in the context of the logged in user
    }
}

Non Vulnerable :

public class TestController
{
    [HttpPost]
    [ValidateAntiForgeryToken] //Annotation added
    public ActionResult ControllerMethod(string input)
    {
        //Do an action in the context of the logged in user
    }
}

Vulnerable :

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable(); // Sensitive: csrf protection is entirely disabled
  // or
    http.csrf().ignoringAntMatchers("/route/"); // Sensitive: csrf protection is disabled for specific routes
  }
}

Non Vulnerable :

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    // http.csrf().disable(); // Compliant
  }
}

Vulnerable :

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;

class VerifyCsrfToken extends Middleware
{
    protected $except = [
        'api/*'
    ]; // Sensitive; disable CSRF protection for a list of routes
}

Non Vulnerable :

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;

class VerifyCsrfToken extends Middleware
{
    protected $except = []; // Compliant
}

Vulnerable :

const csrf = require('csurf');
const express = require('express');

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

const app = express();

// Vulnerable
app.post('/payment', parseForm, (req, res) => {
  res.send('Payment transferred');
});

Non Vulnerable :

const csrf = require('csurf');
const express = require('express');

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

const app = express();

app.post('/payment', parseForm, csrfProtection, (req, res) => { // Non Vulnerable
  res.send('Payment transferred')
});

Vulnerable :

const csrf = require('csurf');
const express = require('express');

app.use(csrf({ cookie: true, ignoreMethods: ["POST", "GET"] })); // Vulnerable

Non Vulnerable :

const csrf = require('csurf');
const express = require('express');

app.use(csrf({ cookie: true, ignoreMethods: ["GET"] })); // Non Vulnerable

Vulnerable :

<p>
  <strong>Credit card #:</strong> {{booking.CardNumber}}
  <input type="hidden" name="booking.CardNumber" value="{{booking.CardNumber}}">
</p>

<p class="buttons">
  <input type="submit" value="Confirm" name="confirm">
  <input type="submit" value="Revise" name="revise">
  <a href="{%url "Hotels.Show" hotel.HotelId%}">Cancel</a>
</p>

Non Vulnerable :

r := gin.Default()
store := cookie.NewStore([]byte("secret"))
r.Use(sessions.Sessions("mysession", store))
r.Use(csrf.Middleware(csrf.Options{
  Secret: "secret345",
  ErrorFunc: func(c *gin.Context) {
    c.String(400, "CSRF token not match")
    c.Abort()
  },
}))

Vulnerable :

Rails.application.routes.draw do    
  root 'home#index'    

  get 'transfer', to: 'transactions#create' # Vulnerable    
end

Non Vulnerable :

Rails.application.routes.draw do    
  root 'home#index'    

  put 'transfer', to: 'transactions#create' # Non Vulnerable    
end

References