preventing csrf in php

With referral checking all your doing is looking to make sure the referer is from your site/system. If the referer does not exist or is from a foreign site then the referal check fails and you may not want to honor whatever request is being made.

In the past problems with various technologies and browsers (flash..et al) allowed forgery of referal headers. Its something to consider. There are several methods using javascript to link to resources where the referal data is not present/passed in the request header.

This behavior varies somewhat between browsers. If you use javascript to submit a form your typically ok. If you use something like window.location most likely you should not expect referal data to be present.

A popular method for CSRF prevention is to not use cookies and always pass state between references... Passing a session token in all links throughout an application.


[Note:] Kohana framework is Deprecated, new fork for Kohana PHP 7 is https://koseven.ga/ and it does support CSRF functionality is Security class.

You can use Official koseven security feature. Here is a link to koseven security class.


To prevent CSRF you'll want to validate a one-time token, POST'ed and associated with the current session. Something like the following . . .

On the page where the user requests to delete a record:

confirm.php

<?php
 session_start();
 $token = isset($_SESSION['delete_customer_token']) ? $_SESSION['delete_customer_token'] : "";
 if (!$token) {
     // generate token and persist for later verification
     // - in practice use openssl_random_pseudo_bytes() or similar instead of uniqid() 
     $token = md5(uniqid());
     $_SESSION['delete_customer_token']= $token;
 }
 session_write_close();
?>
<html>
<body>
<form method="post" action="confirm_save.php">
 <input type="hidden" name="token" value="<?php echo $token; ?>" />
Do you really want to delete?
<input type="submit" value=" Yes " />
<input type="button" value=" No " onclick="history.go(-1);" />
</form>
</body>
</html>

Then when it comes to actually deleting the record:

confirm_save.php

<?php
 session_start();
 // validate token
 $token = isset($_SESSION['delete_customer_token']) ? $_SESSION['delete_customer_token'] : "";
 if ($token && $_POST['token'] === $token) {
   // delete the record
   ...
   // remove token after successful delete
   unset($_SESSION['delete_customer_token']);
 } else {
   // log potential CSRF attack.
 }
 session_write_close();
?>

The token should be hard to guess, unique for each delete request, accepted via $_POST only and expire after a few minutes (expiration not shown in this example).