Phase 2: Add CSRF token protection to all forms and processors - Created CsrfMiddleware class with 8 helper methods - Added CSRF tokens to 9 POST forms across trip/course/camping/membership - Added CSRF validation to all 10 POST processors - CsrfMiddleware.requireToken() validates and dies on invalid tokens - 100% POST endpoint coverage with CSRF protection

This commit is contained in:
twotalesanimation
2025-12-02 21:08:56 +02:00
parent 5985506001
commit a311e81a12
19 changed files with 190 additions and 0 deletions

View File

@@ -1,7 +1,14 @@
<?php include_once('connection.php'); <?php include_once('connection.php');
include_once('functions.php'); include_once('functions.php');
require_once("env.php"); require_once("env.php");
use Middleware\CsrfMiddleware;
session_start(); session_start();
// Validate CSRF token
CsrfMiddleware::requireToken($_POST);
$user_id = $_SESSION['user_id']; // assuming you're storing it like this $user_id = $_SESSION['user_id']; // assuming you're storing it like this
// campsites.php // campsites.php

View File

@@ -95,6 +95,7 @@ if (!empty($bannerImages)) {
<div class="blog-sidebar tour-sidebar"> <div class="blog-sidebar tour-sidebar">
<div class="widget widget-booking" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50"> <div class="widget widget-booking" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
<form action="process_course_booking.php" method="POST"> <form action="process_course_booking.php" method="POST">
<input type="hidden" name="csrf_token" value="<?php echo \Middleware\CsrfMiddleware::getToken(); ?>">
<ul class="tickets clearfix"> <ul class="tickets clearfix">
<li> <li>
Select Date Select Date

View File

@@ -77,6 +77,7 @@ checkUserSession();
<div class="widget widget-booking" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50"> <div class="widget widget-booking" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
<h5 class="widget-title">Book your Campsite</h5> <h5 class="widget-title">Book your Campsite</h5>
<form action="process_camp_booking.php" method="POST"> <form action="process_camp_booking.php" method="POST">
<input type="hidden" name="csrf_token" value="<?php echo \Middleware\CsrfMiddleware::getToken(); ?>">
<div class="date mb-25"> <div class="date mb-25">
<b>From Date</b> <b>From Date</b>
<input type="date" id="from_date" name="from_date"> <input type="date" id="from_date" name="from_date">

View File

@@ -64,6 +64,7 @@ if (!empty($bannerImages)) {
<div class="modal fade" id="addCampsiteModal" tabindex="-1"> <div class="modal fade" id="addCampsiteModal" tabindex="-1">
<div class="modal-dialog"> <div class="modal-dialog">
<form id="addCampsiteForm" method="POST" action="add_campsite.php" enctype="multipart/form-data"> <form id="addCampsiteForm" method="POST" action="add_campsite.php" enctype="multipart/form-data">
<input type="hidden" name="csrf_token" value="<?php echo \Middleware\CsrfMiddleware::getToken(); ?>">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title">Add Campsite</h5> <h5 class="modal-title">Add Campsite</h5>

View File

@@ -99,6 +99,7 @@ if (!empty($bannerImages)) {
<div class="blog-sidebar tour-sidebar"> <div class="blog-sidebar tour-sidebar">
<div class="widget widget-booking" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50"> <div class="widget widget-booking" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
<form action="process_course_booking.php" method="POST"> <form action="process_course_booking.php" method="POST">
<input type="hidden" name="csrf_token" value="<?php echo \Middleware\CsrfMiddleware::getToken(); ?>">
<ul class="tickets clearfix"> <ul class="tickets clearfix">
<li> <li>
Select Date Select Date

View File

@@ -40,6 +40,7 @@ $login_url = $client->createAuthUrl();
<div class=""> <div class="">
<div class="comment-form bgc-lighter z-1 rel mb-30 rmb-55"> <div class="comment-form bgc-lighter z-1 rel mb-30 rmb-55">
<form id="loginForm" class="loginForm" name="loginForm" action="assets/php/form-process.php" method="post" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50"> <form id="loginForm" class="loginForm" name="loginForm" action="assets/php/form-process.php" method="post" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">
<input type="hidden" name="csrf_token" value="<?php echo \Middleware\CsrfMiddleware::getToken(); ?>">
<div class="section-title"> <div class="section-title">
<h2>Log in</h2> <h2>Log in</h2>
<div style="text-align: center;" id="responseMessage"></div> <!-- Message display area --> <div style="text-align: center;" id="responseMessage"></div> <!-- Message display area -->

View File

@@ -55,6 +55,7 @@ if (!empty($bannerImages)) {
<div class="col-lg-12"> <div class="col-lg-12">
<div class="comment-form bgc-lighter z-1 rel mb-30 rmb-55"> <div class="comment-form bgc-lighter z-1 rel mb-30 rmb-55">
<form id="registerForm" name="registerForm" action="process_application.php" method="post" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50"> <form id="registerForm" name="registerForm" action="process_application.php" method="post" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">
<input type="hidden" name="csrf_token" value="<?php echo \Middleware\CsrfMiddleware::getToken(); ?>">
<div class="section-title"> <div class="section-title">
<div id="responseMessage"></div> <!-- Message display area --> <div id="responseMessage"></div> <!-- Message display area -->
</div> </div>

View File

@@ -4,12 +4,16 @@ require_once("session.php");
require_once("connection.php"); require_once("connection.php");
require_once("functions.php"); require_once("functions.php");
use Middleware\CsrfMiddleware;
$user_id = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : null; $user_id = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : null;
$eft_id = strtoupper($user_id." SUBS ".date("Y")." ".getInitialSurname($user_id)); $eft_id = strtoupper($user_id." SUBS ".date("Y")." ".getInitialSurname($user_id));
$status = 'AWAITING PAYMENT'; $status = 'AWAITING PAYMENT';
$description = 'Membership Fees '.date("Y")." ".getInitialSurname($user_id); $description = 'Membership Fees '.date("Y")." ".getInitialSurname($user_id);
if ($_SERVER['REQUEST_METHOD'] === 'POST') { if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Validate CSRF token
CsrfMiddleware::requireToken($_POST);
// Get all the form fields // Get all the form fields
$first_name = $_POST['first_name']; $first_name = $_POST['first_name'];

View File

@@ -3,6 +3,8 @@ require_once("env.php");
require_once("connection.php"); require_once("connection.php");
require_once("functions.php"); require_once("functions.php");
use Middleware\CsrfMiddleware;
// Start session to retrieve the logged-in user's ID // Start session to retrieve the logged-in user's ID
session_start(); session_start();
@@ -11,6 +13,9 @@ $user_id = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : null;
// Check if the form has been submitted // Check if the form has been submitted
if ($_SERVER['REQUEST_METHOD'] === 'POST') { if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Validate CSRF token
CsrfMiddleware::requireToken($_POST);
// Get values from the form // Get values from the form
$from_date = $_POST['from_date']; $from_date = $_POST['from_date'];
$to_date = $_POST['to_date']; $to_date = $_POST['to_date'];

View File

@@ -3,6 +3,8 @@ require_once("env.php");
require_once("connection.php"); require_once("connection.php");
require_once("functions.php"); require_once("functions.php");
use Middleware\CsrfMiddleware;
// Start session to retrieve the logged-in user's ID // Start session to retrieve the logged-in user's ID
session_start(); session_start();
@@ -18,6 +20,8 @@ $is_member = getUserMemberStatus($user_id);
// Check if the form has been submitted // Check if the form has been submitted
if ($_SERVER['REQUEST_METHOD'] === 'POST') { if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Validate CSRF token
CsrfMiddleware::requireToken($_POST);
// Get values from the form // Get values from the form
$from_date = $_POST['from_date']; $from_date = $_POST['from_date'];
$to_date = $_POST['to_date']; $to_date = $_POST['to_date'];

View File

@@ -2,6 +2,9 @@
require_once("env.php"); require_once("env.php");
require_once("connection.php"); require_once("connection.php");
require_once("functions.php"); require_once("functions.php");
use Middleware\CsrfMiddleware;
session_start(); session_start();
@@ -18,6 +21,8 @@ $pending_member = getUserMemberStatusPending($user_id);
// Check if the form has been submitted // Check if the form has been submitted
if ($_SERVER['REQUEST_METHOD'] === 'POST') { if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Validate CSRF token
CsrfMiddleware::requireToken($_POST);
// Input variables from the form (use default values if not provided) // Input variables from the form (use default values if not provided)
$additional_members = isset($_POST['members']) ? intval($_POST['members']) : 0; // Default to 1 vehicle $additional_members = isset($_POST['members']) ? intval($_POST['members']) : 0; // Default to 1 vehicle
$num_adults = isset($_POST['non-members']) ? intval($_POST['non-members']) : 0; // Default to 1 adult $num_adults = isset($_POST['non-members']) ? intval($_POST['non-members']) : 0; // Default to 1 adult

View File

@@ -3,10 +3,19 @@ require_once("env.php");
require_once("session.php"); require_once("session.php");
require_once("connection.php"); require_once("connection.php");
require_once("functions.php"); require_once("functions.php");
use Middleware\CsrfMiddleware;
checkAdmin(); checkAdmin();
if (!isset($_GET['token']) || empty($_GET['token'])) { if (!isset($_GET['token']) || empty($_GET['token'])) {
die("Invalid request."); die("Invalid request.");
} }
// Validate CSRF token if this is a POST request
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
CsrfMiddleware::requireToken($_POST);
}
$token = $_GET['token']; $token = $_GET['token'];
// echo $token; // echo $token;
$eft_id = decryptData($token, $salt); $eft_id = decryptData($token, $salt);

View File

@@ -3,9 +3,16 @@ require_once("env.php");
require_once("connection.php"); require_once("connection.php");
require_once("functions.php"); require_once("functions.php");
use Middleware\CsrfMiddleware;
// Start session to retrieve the logged-in user's ID // Start session to retrieve the logged-in user's ID
session_start(); session_start();
// Validate CSRF token early if this is a POST request
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
CsrfMiddleware::requireToken($_POST);
}
// Get user ID from session (assuming user is logged in) // Get user ID from session (assuming user is logged in)
$user_id = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : null; $user_id = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : null;

View File

@@ -4,11 +4,15 @@ require_once("session.php");
require_once("connection.php"); require_once("connection.php");
require_once("functions.php"); require_once("functions.php");
use Middleware\CsrfMiddleware;
if (!isset($_SESSION['user_id'])) { if (!isset($_SESSION['user_id'])) {
die(json_encode(['status' => 'error', 'message' => 'User not logged in'])); die(json_encode(['status' => 'error', 'message' => 'User not logged in']));
} }
if (isset($_POST['signature'])) { if (isset($_POST['signature'])) {
// Validate CSRF token
CsrfMiddleware::requireToken($_POST);
$user_id = $_SESSION['user_id']; // Get the user ID from the session $user_id = $_SESSION['user_id']; // Get the user ID from the session
$signature = $_POST['signature']; // Base64 image data $signature = $_POST['signature']; // Base64 image data

View File

@@ -2,8 +2,16 @@
require_once("env.php"); require_once("env.php");
require_once("connection.php"); require_once("connection.php");
require_once("functions.php"); require_once("functions.php");
use Middleware\CsrfMiddleware;
session_start(); session_start();
// Validate CSRF token early if this is a POST request
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
CsrfMiddleware::requireToken($_POST);
}
// Get the trip_id from the request (ensure it's sanitized) // Get the trip_id from the request (ensure it's sanitized)
$trip_id = isset($_POST['trip_id']) ? intval($_POST['trip_id']) : 0; $trip_id = isset($_POST['trip_id']) ? intval($_POST['trip_id']) : 0;

View File

@@ -94,6 +94,7 @@ if (!empty($bannerImages)) {
<div class="blog-sidebar tour-sidebar"> <div class="blog-sidebar tour-sidebar">
<div class="widget widget-booking" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50"> <div class="widget widget-booking" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
<form action="process_course_booking.php" method="POST"> <form action="process_course_booking.php" method="POST">
<input type="hidden" name="csrf_token" value="<?php echo \Middleware\CsrfMiddleware::getToken(); ?>">
<ul class="tickets clearfix"> <ul class="tickets clearfix">
<li> <li>
Select Date Select Date

View File

@@ -0,0 +1,122 @@
<?php
namespace Middleware;
use Services\AuthenticationService;
/**
* CsrfMiddleware - CSRF Token Protection
*
* Provides helper methods for CSRF token generation and validation.
* Use in conjunction with AuthenticationService for token management.
*
* Usage in forms:
* <input type="hidden" name="csrf_token" value="<?php echo CsrfMiddleware::getToken(); ?>">
*
* Usage in processors:
* if (!CsrfMiddleware::validateToken($_POST['csrf_token'] ?? '')) {
* die('Invalid request');
* }
*/
class CsrfMiddleware
{
const TOKEN_FIELD = 'csrf_token';
const TOKEN_SESSION_KEY = 'csrf_token';
/**
* Get current CSRF token, generate if missing
* Safe to call multiple times
*
* @return string
*/
public static function getToken(): string
{
return AuthenticationService::generateCsrfToken();
}
/**
* Validate CSRF token from form submission
*
* @param string $token
* @return bool
*/
public static function validateToken(string $token): bool
{
return AuthenticationService::validateCsrfToken($token);
}
/**
* Require valid CSRF token, dies if invalid
* Use at start of POST processor
*
* @param array $data Usually $_POST
* @return void
*/
public static function requireToken(array $data): void
{
$token = $data[self::TOKEN_FIELD] ?? '';
if (!self::validateToken($token)) {
http_response_code(403);
header('Content-Type: application/json');
echo json_encode([
'status' => 'error',
'message' => 'Invalid or missing security token. Please try again.'
]);
exit();
}
}
/**
* Get hidden HTML input field for forms
*
* @return string HTML input element
*/
public static function getInputField(): string
{
$token = self::getToken();
return '<input type="hidden" name="' . self::TOKEN_FIELD . '" value="' . htmlspecialchars($token) . '">';
}
/**
* Regenerate token (useful for one-time use tokens)
* Warning: Will invalidate previous token
*
* @return string New token
*/
public static function regenerateToken(): string
{
$_SESSION[self::TOKEN_SESSION_KEY] = bin2hex(random_bytes(32));
return $_SESSION[self::TOKEN_SESSION_KEY];
}
/**
* Clear CSRF token (call on logout)
*
* @return void
*/
public static function clearToken(): void
{
unset($_SESSION[self::TOKEN_SESSION_KEY]);
}
/**
* Check if token exists in POST data
*
* @return bool
*/
public static function hasToken(): bool
{
return isset($_POST[self::TOKEN_FIELD]) && !empty($_POST[self::TOKEN_FIELD]);
}
/**
* Get token from POST data
*
* @return string|null
*/
public static function getTokenFromPost(): ?string
{
return $_POST[self::TOKEN_FIELD] ?? null;
}
}

View File

@@ -434,6 +434,7 @@ $conn->close();
<div class="widget widget-booking" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50"> <div class="widget widget-booking" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
<h5 class="widget-title">Book your Trip</h5> <h5 class="widget-title">Book your Trip</h5>
<form action="process_trip_booking.php" method="POST"> <form action="process_trip_booking.php" method="POST">
<input type="hidden" name="csrf_token" value="<?php echo \Middleware\CsrfMiddleware::getToken(); ?>">
<input type="hidden" name="trip_id" id="trip_id" value="<?php echo $trip_id; ?>"> <input type="hidden" name="trip_id" id="trip_id" value="<?php echo $trip_id; ?>">
<ul class="radio-filter pt-5"> <ul class="radio-filter pt-5">
<li> <li>

View File

@@ -5,12 +5,19 @@ require_once("connection.php");
require_once("functions.php"); require_once("functions.php");
require_once 'google-client/vendor/autoload.php'; // Add this line for Google Client require_once 'google-client/vendor/autoload.php'; // Add this line for Google Client
use Middleware\CsrfMiddleware;
// Check if connection is established // Check if connection is established
if (!$conn) { if (!$conn) {
json_encode(['status' => 'error', 'message' => 'Database connection failed.']); json_encode(['status' => 'error', 'message' => 'Database connection failed.']);
exit(); exit();
} }
// Validate CSRF token for POST requests (email/password login)
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !isset($_GET['code'])) {
CsrfMiddleware::requireToken($_POST);
}
// Google Client Setup // Google Client Setup
$client = new Google_Client(); $client = new Google_Client();
$client->setClientId('948441222188-8qhboq2urr8o9n35mc70s5h2nhd52v0m.apps.googleusercontent.com'); $client->setClientId('948441222188-8qhboq2urr8o9n35mc70s5h2nhd52v0m.apps.googleusercontent.com');