From de376d04d124b6b9898704a3037140982cfac3ea Mon Sep 17 00:00:00 2001 From: billz Date: Sun, 23 Mar 2025 23:13:29 -0700 Subject: [PATCH] Initial commit --- src/RaspAP/Tokens/CSRFTokenizer.php | 114 ++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 src/RaspAP/Tokens/CSRFTokenizer.php diff --git a/src/RaspAP/Tokens/CSRFTokenizer.php b/src/RaspAP/Tokens/CSRFTokenizer.php new file mode 100644 index 00000000..b86e2f6a --- /dev/null +++ b/src/RaspAP/Tokens/CSRFTokenizer.php @@ -0,0 +1,114 @@ + + * @author Martin Glaß + * @license https://github.com/raspap/raspap-webgui/blob/master/LICENSE + */ + +declare(strict_types=1); + +namespace RaspAP\Tokens; + +class CSRFTokenizer +{ + + // Constructor + public function __construct() + { + $this->ensureSession(); + if ($this->csrfValidateRequest() && !$this->CSRFValidate()) { + $this->handleInvalidCSRFToken(); + } + } + + /** + * Saves a CSRF token in the session + */ + public function ensureCSRFSessionToken(): void + { + if (empty($_SESSION['csrf_token'])) { + $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); + } + } + + /** + * Add CSRF Token to form + */ + public function CSRFTokenFieldTag(): string + { + $token = htmlspecialchars($_SESSION['csrf_token']); + return ''; + } + + /** + * Returns a CSRF meta tag (for use with xhr, for example) + */ + public function CSRFMetaTag(): string + { + $token = htmlspecialchars($_SESSION['csrf_token']); + return ''; + } + + /** + * Validates a CSRF Token + * + * @param string $token + */ + public function CSRFValidate(string $token): bool + { + if(isset($token) { + $header_token = $_SERVER['HTTP_X_CSRF_TOKEN']; + + if (empty($token) && empty($header_token)) { + return false; + } + $request_token = $token; + if (empty($token)) { + $request_token = $header_token; + } + if (hash_equals($_SESSION['csrf_token'], $request_token)) { + return true; + } else { + error_log('CSRF violation'); + return false; + } + } + } + + /** + * Should the request be CSRF-validated? + */ + public function csrfValidateRequest(): string + { + $request_method = strtolower($_SERVER['REQUEST_METHOD']); + return in_array($request_method, [ "post", "put", "patch", "delete" ]); + } + + /** + * Handle invalid CSRF + */ + public function handleInvalidCSRFToken(): string + { + if (function_exists('http_response_code')) { + http_response_code(500); + echo 'Invalid CSRF token'; + } else { + header('HTTP/1.1 500 Internal Server Error'); + header('Content-Type: text/plain'); + echo 'Invalid CSRF token'; + } + exit; + } + + protected function ensureSession() + { + if (session_status() == PHP_SESSION_NONE) { + session_start(); + } + } +} +