Cross-Site Request Forgery (CSRF) is a web security vulnerability attack that occurs when a malicious website or program causes a user’s web browser to perform an unwanted action on a trusted site when the user is authenticated. The attack allows an attacker to induce users to perform actions that they do not intend to perform. In a successful CSRF attack, the attacker causes the victim user to carry out an action unintentionally.
Most web application frameworks have built-in CSRF features (i.e. Laravel CSRF https://laravel.com/docs/9.x/csrf). Below is an example where created an easy and simple way protect against CSRF.
index.php
<?php
session_start();
//Generate CSRF token
function csrf_token()
{
if (empty($_SESSION['csrf']))
{
if (function_exists('random_bytes'))
{
$_SESSION['csrf'] = bin2hex(random_bytes(32));
}
else if (function_exists('mcrypt_create_iv'))
{
$_SESSION['csrf'] = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
} else
{
$_SESSION['csrf'] = bin2hex(openssl_random_pseudo_bytes(32));
}
}
$token = $_SESSION['csrf'];
return $token;
}
//Check CSRF data
function check_csrf($token)
{
if(isset($token) && empty($token))
{
echo '<div class="alert alert-warning m-2" role="alert"><b>Error:</b> Incorrect <abbr title="Cross Site Request Forgery">CSRF</abbr> token is missing.</div>';
header($_SERVER['SERVER_PROTOCOL'] . ' 405 Method Not Allowed');
exit;
}
//if (!hash_equals($_SESSION['csrf'], $_POST['csrf'])) die();
elseif (!hash_equals($_SESSION['csrf'], $_POST['csrf']))
{
// show an error message
echo '<div class="alert alert-danger m-2" role="alert"><b>Error:</b> Incorrect <abbr title="Cross Site Request Forgery">CSRF</abbr> token.</div>';
// return 405 http status code
header($_SERVER['SERVER_PROTOCOL'] . ' 405 Method Not Allowed');
exit;
}
}
//Sanitize user data
function cleanInput($data) {
$data = trim($data);
$data = stripslashes($data);
$data = addslashes($data);
//$data = htmlspecialchars($data);
return $data;
}
if(isset($_POST['submit']))
{
//check CSRF
check_csrf($_POST['csrf']);
//Form data
$sFirstName = cleanInput($_POST['sFirstName']);
$sLastName = cleanInput($_POST['sLastName']);
$sAddress1 = cleanInput($_POST['sAddress1']);
$sAddress2 = cleanInput($_POST['sAddress2']);
$sCity = cleanInput($_POST['sCity']);
$sStateCode = cleanInput($_POST['sStateCode']);
$sZipCode = cleanInput($_POST['sZipCode']);
$sEmailAddress = cleanInput($_POST['sEmailAddress']);
$dBirthDate = cleanInput($_POST['dBirthDate']);
$bOptIn = cleanInput($_POST['bOptIn']);
//Do insert, update,
}
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://getbootstrap.com/docs/5.2/assets/css/docs.css" rel="stylesheet">
<title>CSRF Example</title>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body class="p-3 m-0 border-0 bd-example">
<!-- Example Code -->
<form class="row g-3" action="" method="post">
<!-- hidden CSRF token -->
<input type="hidden" class="form-control" id="csrf" name="csrf" placeholder="csrf" value="<?php echo csrf_token();?>">
<div class="col-md-6">
<label for="sFirstName" class="form-label">First Name</label>
<input type="text" class="form-control" id="sFirstName" name="sFirstName">
</div>
<div class="col-md-6">
<label for="sLastName" class="form-label">Last Name</label>
<input type="text" class="form-control" id="sLastName" name="sLastName">
</div>
<div class="col-12">
<label for="sAddress1" class="form-label">Address</label>
<input type="text" class="form-control" id="sAddress1" placeholder="1234 Main St" name="sAddress1">
</div>
<div class="col-12">
<label for="sAddress2" class="form-label">Address 2</label>
<input type="text" class="form-control" id="sAddress2" placeholder="Apartment, studio, or floor" name="sAddress2">
</div>
<div class="col-md-6">
<label for="sCity" class="form-label">City</label>
<input type="text" class="form-control" id="sCity" name="sCity">
</div>
<div class="col-md-4">
<label for="sStateCode" class="form-label">State</label>
<select id="sStateCode" class="form-select">
<option selected="">Choose...</option>
<option>...</option>
</select>
</div>
<div class="col-md-2">
<label for="sZipCode" class="form-label">Zip</label>
<input type="text" class="form-control" id="sZipCode" name="sZipCode">
</div>
<div class="col-md-6">
<label for="sEmailAddress" class="form-label">Email</label>
<input type="email" class="form-control" id="sEmailAddress" name="sEmailAddress">
</div>
<div class="col-md-6">
<label for="dBirthDate" class="form-label">Date of Birth</label>
<input type="date" class="form-control" id="dBirthDate" name="dBirthDate">
</div>
<div class="col-12">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="bOptIn" name="bOptIn">
<label class="form-check-label" for="gridCheck">
Check me out
</label>
</div>
</div>
<div class="col-12">
<button type="submit" class="btn btn-primary" name="submit" id="submit">Sign in</button>
</div>
</form>
<!-- End Example Code -->
</body>
</html>
Hope it will help against CSRF attack.