bhylu.com

Advertisements

PHP CSRF Protection

A CSRF check helps distinguish a legitimate form submission from a request caused by another site. Bind the token to the visitor’s server-side session and verify it before changing state.

How it works

Generate an unpredictable token, retain it server-side and return it to the intended form/client. On POST, require a scalar token and compare it using hash_equals with the stored value first. The JSON GET in this standalone lab makes the mechanism easy to test; a normal HTML form can carry the token in a hidden input. CSRF protection does not authenticate the visitor or replace authorisation, and cross-site scripting can undermine a token-based defence.

Run it locally

Save this standalone lab file in a separate local folder. Start a PHP development server on an unused loopback port, for example php -S 127.0.0.1:8090 -t . . Open the shown filename through that server, not a file URL. Exercise GET and POST as described. This is not a POST endpoint on Bhylu, and the built-in development server is not a production server.

php -l csrf.php
php -S 127.0.0.1:8090 -t .

Download this source as a local PHP lab file. Keep lab files separate from the Bhylu project and production data.

Example

PHP 8.2+ · csrf.php

<?php
declare(strict_types=1);

session_set_cookie_params(["httponly"=>true,"samesite"=>"Lax","secure"=>isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] !== "off"]);
session_start();
$_SESSION["lab_csrf"] ??= bin2hex(random_bytes(32));
header("Content-Type: application/json; charset=utf-8");
if (($_SERVER["REQUEST_METHOD"] ?? "GET") === "GET") { echo json_encode(["token"=>$_SESSION["lab_csrf"]]); exit; }
if ($_SERVER["REQUEST_METHOD"] !== "POST") { http_response_code(405); echo json_encode(["error"=>"Use POST"]); exit; }
$token = $_POST["token"] ?? null;
if (!is_string($token) || !hash_equals($_SESSION["lab_csrf"], $token)) { http_response_code(403); echo json_encode(["error"=>"Invalid token"]); exit; }
echo json_encode(["accepted"=>true]);

Expected result

GET supplies a session token; a matching POST returns {"accepted":true}; missing tokens return 403.

The review retains the session cookie, reads the actual generated token and exercises accepted and rejected POSTs. No loan is created by this fixture. A production flow must decide token lifetime, session expiry and the complete set of protected state-changing endpoints instead of checking only one convenient form.

Requests to check

  • GET csrf.php → status 200; retain the actual returned token and session cookie for the next request.
  • POST csrf.php → status 403; form fields: .
  • POST csrf.php → status 200; form fields: token.

Use a local browser form or HTTP client. A CSRF token from one session does not authorise a different session. The automated review uses actual HTTP requests, not just command-line output.

Check the official PHP manual for detailed version and API contracts.

Advertisements