From d82a08f77bb7b7a8a177ea367309cdcaeaf69299 Mon Sep 17 00:00:00 2001 From: janis steiner Date: Wed, 6 May 2026 09:07:48 +0200 Subject: [PATCH] adding enhanced csrf protection --- app-code/account/index.php | 19 +++++++++++--- app-code/account/manage_users.php | 16 +++++++++++- app-code/api/account/update_2fa.php | 4 +++ app-code/api/account/update_message.php | 4 +++ app-code/api/account/update_passkey.php | 1 + app-code/api/account/update_pw.php | 4 +++ app-code/api/account/update_user_data.php | 1 + app-code/api/login/check_mfa.php | 4 +++ app-code/api/login/check_passkey.php | 1 + app-code/api/login/check_pw.php | 4 +++ app-code/api/login/delete_keepmeloggedin.php | 5 ++++ app-code/api/login/keepmeloggedin.php | 4 +++ app-code/api/login/reset_pw.php | 5 +++- app-code/api/login/send_reset_link.php | 5 ++++ app-code/api/login/set_username.php | 4 +++ app-code/api/manage/delete_user.php | 1 + app-code/api/register/register_user.php | 1 + app-code/api/utils/security.php | 26 ++++++++++++++++++++ app-code/index.php | 2 ++ app-code/login/keepmeloggedin.php | 2 ++ app-code/login/mfa.php | 2 ++ app-code/login/passkey.php | 4 +++ app-code/login/pw.php | 9 ++++++- app-code/login/reset_pw.php | 9 ++++++- app-code/register/index.php | 2 ++ 25 files changed, 132 insertions(+), 7 deletions(-) diff --git a/app-code/account/index.php b/app-code/account/index.php index 228669d..5e3e828 100644 --- a/app-code/account/index.php +++ b/app-code/account/index.php @@ -17,6 +17,7 @@ if (!isset($_SESSION["logged_in"]) || $_SESSION["logged_in"] !== true) { @@ -259,7 +260,8 @@ if (!isset($_SESSION["logged_in"]) || $_SESSION["logged_in"] !== true) { fetch('/api/account/update_user_data.php', { method: 'POST', headers: { - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + 'X-CSRF-Token': window.csrfToken }, body: JSON.stringify(updatedUser) }) @@ -306,7 +308,8 @@ if (!isset($_SESSION["logged_in"]) || $_SESSION["logged_in"] !== true) { fetch('/api/account/update_pw.php', { method: 'POST', headers: { - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + 'X-CSRF-Token': window.csrfToken }, body: JSON.stringify(passwordData) }) @@ -346,6 +349,7 @@ if (!isset($_SESSION["logged_in"]) || $_SESSION["logged_in"] !== true) { method: 'POST', headers: { 'Content-Type': 'application/json', + 'X-CSRF-Token': window.csrfToken, }, body: JSON.stringify({ enable_2fa: isEnabled, // Send the new state of 2FA @@ -384,6 +388,7 @@ if (!isset($_SESSION["logged_in"]) || $_SESSION["logged_in"] !== true) { method: 'POST', headers: { 'Content-Type': 'application/json', + 'X-CSRF-Token': window.csrfToken, }, body: JSON.stringify({ enable_message: isEnabled, // Send the new state of 2FA @@ -476,6 +481,9 @@ function generate2FAQRCode(issuer, accountName, secret) { rep = await window.fetch('/api/account/update_passkey.php?fn=processCreate' + getGetParams(), { //rep = await window.fetch('/test/server.php?fn=processCreate' + getGetParams(), { method : 'POST', + headers : { + 'X-CSRF-Token': window.csrfToken + }, body : JSON.stringify(authenticatorAttestationResponse), cache : 'no-cache' }); @@ -620,7 +628,12 @@ function generate2FAQRCode(issuer, accountName, secret) { } } function delete_all_logmein(){ - fetch("/api/login/delete_keepmeloggedin.php"); + fetch("/api/login/delete_keepmeloggedin.php", { + method: "POST", + headers: { + "X-CSRF-Token": window.csrfToken + } + }); } diff --git a/app-code/account/manage_users.php b/app-code/account/manage_users.php index 4092063..d9c5cf8 100644 --- a/app-code/account/manage_users.php +++ b/app-code/account/manage_users.php @@ -1,3 +1,11 @@ + @@ -6,6 +14,7 @@ User Management @@ -58,7 +67,12 @@ if (!confirm('Are you sure you want to delete this user?')) return; try { - const response = await fetch(`/api/manage/delete_user.php?id=${userId}`, { method: 'DELETE' }); + const response = await fetch(`/api/manage/delete_user.php?id=${userId}`, { + method: 'DELETE', + headers: { + 'X-CSRF-Token': window.csrfToken + } + }); const data = await response.json(); if (data.success) { diff --git a/app-code/api/account/update_2fa.php b/app-code/api/account/update_2fa.php index 288e85e..c3e4d1d 100644 --- a/app-code/api/account/update_2fa.php +++ b/app-code/api/account/update_2fa.php @@ -2,7 +2,11 @@ include "../utils/security.php"; secure_session_start(); require_same_origin_request(); +require_csrf_token(); header('Content-Type: application/json'); +if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + json_response(['success' => false, 'message' => 'Invalid request method.'], 405); +} // Check if the user is logged in require_logged_in(); diff --git a/app-code/api/account/update_message.php b/app-code/api/account/update_message.php index 5f881a4..9fbebc5 100644 --- a/app-code/api/account/update_message.php +++ b/app-code/api/account/update_message.php @@ -2,7 +2,11 @@ include "../utils/security.php"; secure_session_start(); require_same_origin_request(); +require_csrf_token(); header('Content-Type: application/json'); +if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + json_response(['success' => false, 'message' => 'Invalid request method.'], 405); +} // Check if the user is logged in require_logged_in(); diff --git a/app-code/api/account/update_passkey.php b/app-code/api/account/update_passkey.php index cfdd109..7b92771 100644 --- a/app-code/api/account/update_passkey.php +++ b/app-code/api/account/update_passkey.php @@ -6,6 +6,7 @@ header('Content-Type: application/json'); include "../utils/security.php"; secure_session_start(); require_same_origin_request(); +require_csrf_token(); require_once 'WebAuthn.php'; diff --git a/app-code/api/account/update_pw.php b/app-code/api/account/update_pw.php index c3e14f9..1c49c4d 100644 --- a/app-code/api/account/update_pw.php +++ b/app-code/api/account/update_pw.php @@ -2,7 +2,11 @@ include "../utils/security.php"; secure_session_start(); require_same_origin_request(); +require_csrf_token(); header('Content-Type: application/json'); +if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + json_response(['success' => false, 'message' => 'Invalid request method.'], 405); +} // Check if the user is logged in require_logged_in(); diff --git a/app-code/api/account/update_user_data.php b/app-code/api/account/update_user_data.php index bcb782e..4b8320f 100644 --- a/app-code/api/account/update_user_data.php +++ b/app-code/api/account/update_user_data.php @@ -2,6 +2,7 @@ include "../utils/security.php"; secure_session_start(); require_same_origin_request(); +require_csrf_token(); header('Content-Type: application/json'); // Check if the user is logged in diff --git a/app-code/api/login/check_mfa.php b/app-code/api/login/check_mfa.php index 11d9c22..5d7b7b5 100644 --- a/app-code/api/login/check_mfa.php +++ b/app-code/api/login/check_mfa.php @@ -2,7 +2,11 @@ include "../utils/security.php"; secure_session_start(); require_same_origin_request(); +require_csrf_token(); header('Content-Type: application/json'); +if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + json_response(['success' => false, 'message' => 'Invalid request method.'], 405); +} $send_to=$_SESSION["end_url"]; include "../../config/config.php"; diff --git a/app-code/api/login/check_passkey.php b/app-code/api/login/check_passkey.php index f2f2c8b..1874db9 100644 --- a/app-code/api/login/check_passkey.php +++ b/app-code/api/login/check_passkey.php @@ -3,6 +3,7 @@ header('Content-Type: application/json'); include "../utils/security.php"; secure_session_start(); require_same_origin_request(); +require_csrf_token(); require_once 'WebAuthn.php'; include "../../config/config.php"; $conn = new mysqli($DB_SERVERNAME, $DB_USERNAME, $DB_PASSWORD,$DB_DATABASE); diff --git a/app-code/api/login/check_pw.php b/app-code/api/login/check_pw.php index 721cd2c..3f58973 100644 --- a/app-code/api/login/check_pw.php +++ b/app-code/api/login/check_pw.php @@ -2,7 +2,11 @@ include "../utils/security.php"; secure_session_start(); require_same_origin_request(); +require_csrf_token(); header('Content-Type: application/json'); +if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + json_response(['success' => false, 'message' => 'Invalid request method.'], 405); +} $send_to=$_SESSION["end_url"]; include "../../config/config.php"; diff --git a/app-code/api/login/delete_keepmeloggedin.php b/app-code/api/login/delete_keepmeloggedin.php index 6c142bc..e10cac8 100644 --- a/app-code/api/login/delete_keepmeloggedin.php +++ b/app-code/api/login/delete_keepmeloggedin.php @@ -2,7 +2,12 @@ include "../utils/security.php"; secure_session_start(); require_same_origin_request(); +require_csrf_token(); header('Content-Type: application/json'); +if ($_SERVER['REQUEST_METHOD'] !== 'POST' && $_SERVER['REQUEST_METHOD'] !== 'DELETE') { + echo json_encode(['success' => false, 'message' => 'Invalid request method.']); + exit; +} $send_to=$_SESSION["end_url"]; require_logged_in(); diff --git a/app-code/api/login/keepmeloggedin.php b/app-code/api/login/keepmeloggedin.php index 49b3eed..f7e572d 100644 --- a/app-code/api/login/keepmeloggedin.php +++ b/app-code/api/login/keepmeloggedin.php @@ -2,7 +2,11 @@ include "../utils/security.php"; secure_session_start(); require_same_origin_request(); +require_csrf_token(); header('Content-Type: application/json'); +if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + json_response(['success' => false, 'message' => 'Invalid request method.'], 405); +} $send_to=$_SESSION["end_url"]; include "../../config/config.php"; diff --git a/app-code/api/login/reset_pw.php b/app-code/api/login/reset_pw.php index be1ba6b..8cf04f1 100644 --- a/app-code/api/login/reset_pw.php +++ b/app-code/api/login/reset_pw.php @@ -1,4 +1,8 @@ 'error', 'message' => 'Invalid request method.']); } ?> - diff --git a/app-code/api/login/send_reset_link.php b/app-code/api/login/send_reset_link.php index 746627d..8368782 100644 --- a/app-code/api/login/send_reset_link.php +++ b/app-code/api/login/send_reset_link.php @@ -2,7 +2,12 @@ include "../utils/security.php"; secure_session_start(); require_same_origin_request(); +require_csrf_token(); header('Content-Type: application/json'); +if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + echo json_encode(['success' => false, 'message' => 'Invalid request method.']); + exit; +} include "../../config/config.php"; include "../utils/get_location.php"; $username=$_SESSION["username"] ?? ""; diff --git a/app-code/api/login/set_username.php b/app-code/api/login/set_username.php index c3dcffa..9f48a14 100644 --- a/app-code/api/login/set_username.php +++ b/app-code/api/login/set_username.php @@ -2,6 +2,10 @@ include "../utils/security.php"; secure_session_start(); require_same_origin_request(); +require_csrf_token(); +if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + json_response(['success' => false, 'message' => 'Invalid request method.'], 405); +} $_SESSION["needs_auth"]=true; $_SESSION["logged_in"]=false; $username = strtolower((string) ($_POST["username"] ?? "")); diff --git a/app-code/api/manage/delete_user.php b/app-code/api/manage/delete_user.php index 907aa84..b71dbbd 100644 --- a/app-code/api/manage/delete_user.php +++ b/app-code/api/manage/delete_user.php @@ -3,6 +3,7 @@ header('Content-Type: application/json'); include "../utils/security.php"; secure_session_start(); require_same_origin_request(); +require_csrf_token(); //check for permisisons if (!isset($_SESSION["logged_in"]) || $_SESSION["logged_in"] !== true || !is_admin_session() ) { echo(json_encode(['success' => false, 'message'=>'not authenticated'])); diff --git a/app-code/api/register/register_user.php b/app-code/api/register/register_user.php index b6d073c..4edce3a 100644 --- a/app-code/api/register/register_user.php +++ b/app-code/api/register/register_user.php @@ -3,6 +3,7 @@ include "../utils/security.php"; secure_session_start(); require_same_origin_request(); +require_csrf_token(); header('Content-Type: application/json'); include "../../config/config.php"; diff --git a/app-code/api/utils/security.php b/app-code/api/utils/security.php index d98a5ad..de3dfe8 100644 --- a/app-code/api/utils/security.php +++ b/app-code/api/utils/security.php @@ -53,6 +53,32 @@ function require_same_origin_request(): void } } +function csrf_token(): string +{ + if (empty($_SESSION['csrf_token']) || !is_string($_SESSION['csrf_token'])) { + $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); + } + + return $_SESSION['csrf_token']; +} + +function print_csrf_script(): void +{ + echo ''; +} + +function require_csrf_token(): void +{ + if (!in_array($_SERVER['REQUEST_METHOD'] ?? 'GET', ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { + return; + } + + $token = $_SERVER['HTTP_X_CSRF_TOKEN'] ?? $_POST['csrf_token'] ?? ''; + if (empty($_SESSION['csrf_token']) || !is_string($token) || !hash_equals($_SESSION['csrf_token'], $token)) { + json_response(['success' => false, 'message' => 'Invalid CSRF token.'], 403); + } +} + function require_logged_in(): void { if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true || empty($_SESSION['id'])) { diff --git a/app-code/index.php b/app-code/index.php index d2f3118..524b35c 100644 --- a/app-code/index.php +++ b/app-code/index.php @@ -25,6 +25,7 @@ if(logmein()==="success"){ Jakach Login @@ -103,6 +104,7 @@ if(logmein()==="success"){ method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', // Form-like data + 'X-CSRF-Token': window.csrfToken, }, body: new URLSearchParams({ username: username, // Send username as form data diff --git a/app-code/login/keepmeloggedin.php b/app-code/login/keepmeloggedin.php index a74e4b1..499fb83 100644 --- a/app-code/login/keepmeloggedin.php +++ b/app-code/login/keepmeloggedin.php @@ -10,6 +10,7 @@ secure_session_start(); Jakach Login @@ -43,6 +44,7 @@ secure_session_start(); method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', // Form-like data + 'X-CSRF-Token': window.csrfToken, }, body: new URLSearchParams({ keepmeloggedin: keepmeloggedin, // Send password as form data diff --git a/app-code/login/mfa.php b/app-code/login/mfa.php index 9773f35..7db277e 100644 --- a/app-code/login/mfa.php +++ b/app-code/login/mfa.php @@ -10,6 +10,7 @@ secure_session_start(); Jakach Login @@ -78,6 +79,7 @@ secure_session_start(); method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', // Form-like data + 'X-CSRF-Token': window.csrfToken, }, body: new URLSearchParams({ twofa_pin: password, // Send password as form data diff --git a/app-code/login/passkey.php b/app-code/login/passkey.php index 2d25e6a..5686dc0 100644 --- a/app-code/login/passkey.php +++ b/app-code/login/passkey.php @@ -10,6 +10,7 @@ secure_session_start(); Jakach Login @@ -106,6 +107,9 @@ async function checkRegistration() { // send to server rep = await window.fetch('/api/login/check_passkey.php?fn=processGet' + getGetParams(), { method:'POST', + headers: { + 'X-CSRF-Token': window.csrfToken + }, body: JSON.stringify(authenticatorAttestationResponse), cache:'no-cache' }); diff --git a/app-code/login/pw.php b/app-code/login/pw.php index 0e63bd5..95dc0e8 100644 --- a/app-code/login/pw.php +++ b/app-code/login/pw.php @@ -10,6 +10,7 @@ secure_session_start(); Jakach Login @@ -81,7 +82,12 @@ secure_session_start();