Anti-CSRF Tokens

I have to solve a security issue that came back from the pen test done by IT security.

Form submission when a user is logged in is handled by always adding User Identity step as first step for your server actions but these are forms submitted when not logged in for instance login and forgot password.

The blurb form security regarding this issue:

No Anti-CSRF tokens were found in a HTML submission form. A cross-site request forgery is an attack that involves forcing a victim to send an HTTP request to a target destination without their knowledge or intent in order to perform an action as the victim. The underlying cause is application functionality using predictable URL/form actions in a repeatable way. The nature of the attack is that CSRF exploits the trust that a web site has for a user. By contrast, cross-site scripting (XSS) exploits the trust that a user has for a web site. Like XSS, CSRF attacks are not necessarily cross-site, but they can be. Cross-site request forgery is also known as CSRF, XSRF, one-click attack, session riding, confused deputy, and sea surf.

Has anyone implemented this using Wappler?

Would just creating a session var and submitting it with the form, then matched server side with a condition if matched then proceed with other actions be the easiest solution for this or is there a more clever way?

Some additional links on the topic:

http://projects.webappsec.org/Cross-Site-Request-Forgery

https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fcwe.mitre.org%2Fdata%2Fdefinitions%2F352.html&data=05|01|mschmidt%40pps.co.za|c91c3b1db5724a18694f08dbf16c3650|bdab13805e3f49619568374632b59406|0|0|638369219308012521|Unknown|TWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D|3000|||&sdata=OHjckMuauA%2FG6ioiw2ZeFW%2BIR0Kx0%2FxyFiiG32h9XKU%3D&reserved=0

1 Like

Yes, that’s what I did some years ago while I was learning web dev :smile:

On a side-note, I privately reported the lack of CSRF protection in July 2022, but no progresses have been made.

2 Likes

I’d like to implement this too, with PHP…

Would love to see the code that creates the session var on the client side and then correctly reads it on the server side.

@George, can any more Wappler elegance be added to this process?

It would be great to have this topic in the documentation and tutorial videos for everyone to understand the issue…

1 Like

It looks like there is an Express middleware called csurf.

Answers from the almighty AI. :slight_smile:

For Node:

In Node.js, to generate a secure anti-CSRF token, you would typically use a library that can create cryptographically strong random tokens. One commonly used package for this purpose is crypto , which is a built-in module in Node.js. Here’s how you can use it to generate an anti-CSRF token:

  1. Import the Crypto Module : You start by requiring the crypto module in your Node.js script.
const crypto = require('crypto');
  1. Generate a Secure Token : Use the randomBytes method to generate a secure random token. This method is asynchronous and provides a buffer with random bytes.
crypto.randomBytes(32, (err, buffer) => {
  if (err) {
    // handle error
    console.error(err);
    return;
  }
  const token = buffer.toString('hex');
  // Now you have a secure random token
  console.log(token);
});

In this example, 32 is the number of bytes to generate. You can adjust this based on your security requirements. The generated token is a buffer, which is then converted to a hex string for easier handling.
3. Storing and Validating the Token :

  • Store the token in the user’s session . When a user logs in or starts a new session, generate a new token and store it in the session.
  • Include the token in forms or requests . When sending a form or making an AJAX request, include this token as part of the submission.
  • Validate the token on the server . When the form or request is received, compare the received token with the one stored in the session. Only proceed if they match.
  1. Use Middleware for Simplification : If you are using Express.js or another web framework, consider using middleware that can automate this process. Middleware like csurf can handle the generation, inclusion, and validation of CSRF tokens in a more streamlined manner.

Remember, proper management of these tokens is crucial. They should be unique per user session and should be checked on every state-changing request (like form submissions or API calls that alter data). This approach helps to safeguard your application against CSRF attacks.

For php:

In PHP, generating and implementing anti-CSRF tokens involves a few straightforward steps. PHP doesn’t have a built-in library specifically for CSRF protection like some frameworks do, so you’ll typically implement this manually or use a third-party library. Here’s how you can manually create and manage anti-CSRF tokens in PHP:

  1. Generate the Token :
  • Use PHP’s bin2hex(random_bytes()) function to generate a secure token. This function creates a string of cryptographically secure pseudo-random bytes and then converts it to hexadecimal representation.
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

In this example, 32 bytes is a good length for the token, providing a high level of security.
2. Store the Token in the Session :

  • Store the generated token in the user’s session. This way, you can compare the token sent with requests to the one stored in the session.
$_SESSION['csrf_token'] = $token;
  1. Include the Token in Forms :
  • Include the token in all forms as a hidden input field. When the form is submitted, this token will be sent along with the other form data.
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
  1. Validate the Token on Form Submission :
  • When a form is submitted, check that the token in the form matches the token stored in the session. If they don’t match, reject the request as it may be a CSRF attack.
if (isset($_POST['csrf_token']) && $_POST['csrf_token'] === $_SESSION['csrf_token']) {
    // process form
} else {
    // error: invalid CSRF token
}
  1. Token Expiry and Regeneration :
  • Consider regenerating the token periodically or on specific actions (like logging in) for enhanced security.
  • Manage the lifecycle of the token carefully, ensuring it’s available when needed but also refreshed to prevent potential exploits.
  1. Cross-Site Scripting (XSS) Protection :
  • Remember that CSRF protection should be accompanied by robust XSS protection. If your application is vulnerable to XSS, attackers might steal the CSRF token.
  1. Testing and Verification :
  • Test your implementation thoroughly. Ensure that your application rejects requests when the CSRF token is missing or incorrect.

This manual approach provides a basic level of CSRF protection. However, if you’re using a PHP framework (like Laravel, Symfony, or CodeIgniter), they often come with built-in CSRF protection mechanisms that are more sophisticated and easier to implement. Always refer to the documentation of the framework you are using for specific guidance.

2 Likes

We can extend Express, so might be easy to implement csurf for node projects.

2 Likes

Hey @kfawcett, thanks soooo much for these details from the overlords! :tada:

1 Like

I’ve just got this method going by putting the following code in the top of my index.php:

<?php 
session_start();
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
?>

Note that it needs the session_start()…!

Then I can pass the token to a server action with a hidden input:

<input id="i_user_setting_csrf" name="csrf_token" type="hidden" class="form-control" value="<?php echo $_SESSION['csrf_token']; ?>">

and read the value of the csrf_token session variable directly in my server action by declaring it in the $_SESSION area to do the comparison.

I believe its essential to tailor the approach for Anti-CSRF based on the specific use case.
We can built our own custom flow for same using below steps:

  1. Generate a Unique token at login and store the token in users session (SC Side) and send it at the time of critical operations e.g. Payment i.e. on form fetch (GET request) bind it as a hidden field on the form and when submitting the form (an SC request), include this token as part of the submission.

  2. Validate the token on the SC side i.e. When the form or request is received, compare the received token with the one stored in the session. Only proceed if they match. Else a 403 Forbidden Page mentioning CSRF failure, Requesting the user to re-authenticate”

CSRF tokens should not be stored in cookies or Browser SS.

2 Likes

I think we should add an integrated option for CSRF tokens @patrick

6 Likes