I’m encountering an issue with CSRF token validation in my PHP application. Specifically, when I try to delete multiple entries using the same CSRF token, I receive a “CSRF attack detected” error message. I believe this issue is related to the CSRF token being used multiple times within the same session without being regenerated.
<?php
session_start();
// Generate a new CSRF token if one doesn't exist
if (!isset($_SESSION['auth_token'])) {
$_SESSION['auth_token'] = bin2hex(random_bytes(20));
}
// Handle delete request
if (isset($_POST["delete_entry"])) {
// Validate CSRF token
if (!isset($_POST['auth_token']) || !isset($_SESSION['auth_token']) || $_SESSION['auth_token'] !== $_POST['auth_token'] || !isset($_POST['target_id'])) {
// If the CSRF token is invalid or missing
echo '<div class="alert alert-danger alert-dismissible fade show" role="alert">
<i class="fas fa-bug"></i>
CSRF attack detected. Please reload the page and try again.<button type="button" class="btn-close"
data-bs-dismiss="alert" aria-label="Close"></button>
</div>';
// Regenerate CSRF token to prevent any further attempts with the same token
$_SESSION['auth_token'] = bin2hex(random_bytes(20));
exit();
} else {
// Proceed with delete operation if the CSRF token is valid
$target_id = htmlspecialchars(strip_tags($antiXss->xss_clean($_POST['target_id'])));
$stmt = $con->prepare("SELECT * FROM jentress_erp WHERE jnum = ? and company=?");
$stmt->bind_param("ss", $target_id, $_SESSION["company"]);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
$_id = $row["id"];
$_path = $row["position"];
$stmt1 = $con->prepare("SELECT * FROM entress_erp_part2 WHERE contact_id = ?");
if ($stmt1 === false) {
die('Prepare failed: ' . htmlspecialchars($con->error));
}
$stmt1->bind_param("i", $_id);
$stmt1->execute();
$result = $stmt1->get_result();
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
$_account = htmlspecialchars($antiXss->xss_clean($row['s_account']), ENT_QUOTES, 'UTF-8');
$_acc_serial_token = htmlspecialchars($antiXss->xss_clean($row['acc_serial_token']), ENT_QUOTES, 'UTF-8');
$_debtor = htmlspecialchars($antiXss->xss_clean($row['s_debtor']), ENT_QUOTES, 'UTF-8');
$_creditor = htmlspecialchars($antiXss->xss_clean($row['s_creditor']), ENT_QUOTES, 'UTF-8');
$stmtu = $con->prepare("SELECT * FROM categories WHERE acc_serial =? AND acc_name=? AND company=?");
$stmtu->bind_param("sss", $_acc_serial_token, $_account, $_SESSION["company"]);
$stmtu->execute();
$resultu = $stmtu->get_result();
if ($resultu->num_rows > 0) {
$rowu = $resultu->fetch_assoc();
$balance = $rowu['ac_balanced'];
$new_balance = $balance - $_debtor + $_creditor;
$stmtu2 = $con->prepare("UPDATE categories SET ac_balanced=? WHERE acc_serial=? AND acc_name=? AND company=?");
$stmtu2->bind_param('ssss', $new_balance, $_acc_serial_token, $_account, $_SESSION["company"]);
if ($stmtu2->execute()) {
$stmt5 = $con->prepare("DELETE FROM jentress_erp WHERE id = ? AND company=?");
$stmt5->bind_param("is", $_id, $_SESSION["company"]);
if ($stmt5->execute()) {
if (isset($_path) && file_exists($_path)) {
unlink($_path);
}
echo '<script>$(document).ready(function(){toastr.success("Entry successfully deleted");}) </script>';
} else {
echo '<script>$(document).ready(function(){toastr.error("Error occurred while deleting the entry");}) </script>';
}
} else {
echo '<script>$(document).ready(function(){toastr.error("Error occurred while updating the balance");}) </script>';
}
} else {
echo '<script>$(document).ready(function(){toastr.error("No data found");}) </script>';
}
}
} else {
echo '<script>$(document).ready(function(){toastr.error("Entry number error");}) </script>';
}
}
} else {
echo '<script>$(document).ready(function(){toastr.error("No data found for this number");}) </script>';
}
// After successful deletion, generate a new token
$_SESSION['auth_token'] = bin2hex(random_bytes(20));
}
}
?>
When trying to delete multiple entries in a single request or making successive delete requests within the same session, the CSRF token validation fails. The error message indicates a potential CSRF attack. This suggests that the CSRF token is being reused or is not being updated properly, causing subsequent requests to fail the CSRF check.
**What I Need Help With:
**
. Understanding why the CSRF token validation is failing when attempting to delete multiple entries.
. Suggestions on how to properly handle CSRF tokens in such scenarios to ensure that multiple deletions can be performed in a single session without issues.
. Best practices for CSRF token management in PHP applications to avoid similar issues.
Thank you!
<!-- Modal -->
<div class="modal fade" id="staticBackdrop" data-bs-backdrop="static"
data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-info">
<h1 class="modal-title fs-5" id="staticBackdropLabel">Are you sure to delete the entry?</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form method="POST" action="">
<div class="mb-3">
<input type="hidden" name="auth_token" value="<?php echo htmlspecialchars(strip_tags($antiXss->xss_clean($_SESSION['auth_token']))); ?>" required>
<input type="hidden" name="target_id" class="form-control" id="recipient-name">
</div>
</div>
<div class="modal-footer">
<button type="submit" name="delete_entry" class="btn btn-danger"><i class="fa-solid fa-trash"></i> delete </button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><i class="fa-solid fa-ban"></i> cancel</button>
</div>
</div>
</form>
</div>
</div>