PHP CSRF Prevention

Steve Clifton
4 min readMar 3, 2019

What is Cross-Site Request Forgery (CSRF) ?

The Open Web Application Security Project (OWASP) have one of the clearest and simplest definitions of what CSRF actually is:

Cross-Site Request Forgery (CSRF) is a type of attack that occurs when a malicious web site, email, blog, instant message, or program causes a user’s web browser to perform an unwanted action on a trusted site when the user is authenticated.

What could a CSRF attack do?

As a CSRF attack requires a user to navigate to the target-website where they are authenticated, the attack is limited to the powers of the user affected. This can range from changing login credentials, submitting forms on behalf of the user, through to more serious actions such as modifying/exporting/deleting database records and exposing sensitive data.

How could this happen?

One very simple way this could happen is by sending an email to a user, lets call them Foo, telling them they have won an awesome prize! Foo is excited, so they click on the link and see a button telling them to claim their prize. When they click on the link, instead of giving them a prize, it actually submits a hidden form populated with their email (which was added to the url in the original email) and a password that the hacker has pre-set.

In the below example, the user may end up landing at their account page (assuming that after a successful password reset they are directed to their account page), which to the user might seem strange, but perhaps not raise any suspicions.

At the same time, a simple ajax alert to the hacker can let them know that the user clicked the button, submitted the form, and what ever their malicious form’s intentions were MIGHT have been executed.

URL : https://hackerssite.com?foo@bar.com
<body>
<form action="https://example.com/resetpassword" method="POST">
<input id="email" type="hidden" name="email" value="">
<input type="hidden" name="password" value="h4x3d">
<button>Claim your prize!</button>
</form>
</body>
<script type="text/javascript">
var email = window.location.search.substr(1);
document.getElementById('email').value = email;
// ajax message to hacker
</script>

What are CSRF tokens?

CSRF tokens, also called request verification codes, are unique session generated codes and are commonly used for form submissions. These codes allow the web application to know that the user submitted the form from their web browser, and not from an outside source. CSRF tokens usually live in the user’s session data and their cookies. A typical flow of events are:

  1. User requests a web page that has a form.
  2. The web application securely generates 2 tokens, one is sent in the form html (as a hidden input), and the other is sent as a cookie.
  3. The user submits the form to the web application, which should contain both the form input token and the cookie value in the http header.
  4. The web application verifies that the two values match, and approves the continuation of the form processing .

If our web application is using this method of request verification, we can see that a malicious website would not be unable to provide both of these tokens and therefore unable to force an unsuspecting user to perform actions on their behalf.

How do we implement CSRF tokens?

Fortunately, most PHP frameworks provide CSRF protection out of the box, however many applications out there are not using a major framework which could make them venerable to these attacks. I recently wrote a very simple PHP package which provides a dead simple way to use CSRF tokens in any web application.

The download and guide can be found at the PHP Packagist repository, as well as at Github

In the below example:

  1. Before the page loads, we call PHP’s native session_start() method, required for starting the users session and defining our super global $_SESSION variable.
  2. In the HTML, we have a simple form, with a PHP echo Csrf::getInputToken(‘home’). Passing in the page name to this method creates two tokens — an input token as well as the cookie token – specific to this particular page. The return from this method IS the hidden input, so ensure it is echo’d correctly.
  3. Once the user submits the form (in this case back to the page), we call a method Csrf::verifyToken('home') which checks the input token and cookie token to ensure they match those submitted. This method returns us true for a succesful request, or false if the tokens are mismatched.
<?php

require_once __DIR__ /*Path To File*/;

use steveclifton\phpcsrftokens\Csrf;

session_start();

if (!empty($_GET['a'])) {
echo (Csrf::verifyToken('home') ? 'success' : 'unsuccessful');
}

?>

<!DOCTYPE html>
<html>
<head><title>Test Script</title></head>
<body>
<form action="?a=submit" method="POST">
<?php echo Csrf::getInputToken('home') ?>
<input type="text" name="name">
<button>Submit!</button>
</form>
</body>
</html>

Good luck!

--

--