CSRF-Schutz auf intern/ ausweiten und BOMs entfernen

intern/ enthaelt dieselben Patientendaten wie der Adminbereich und war
bisher genauso ungeschuetzt. config.inc.php aktiviert den Token-Filter
jetzt fuer beide Verzeichnisse. Eigenen AJAX-Code oder Nicht-HTML-Ausgaben
gibt es dort nicht, die Umstellung betrifft nur Formulare.

intern/login.php rief nach dem Include ein zweites session_start() auf und
setzte danach session.gc_maxlifetime und session.cookie_lifetime per
ini_set(). Beides lief ins Leere, weil die Sitzung zu dem Zeitpunkt schon
laeuft, und erzeugte Warnungen. Die Lebensdauer kommt aus
session_set_cookie_params() in config.inc.php.

13 Dateien begannen mit einem UTF-8-BOM. Die drei Bytes gehen vor dem
Include raus, womit die Header gesendet sind und
session_set_cookie_params() sowie session_start() in config.inc.php
scheitern - genau die Flags, um die es hier geht. Sichtbar wird das nur
ohne output_buffering, aber darauf sollte sich die Sitzungssicherheit
nicht verlassen.

Nachgeprueft mit output_buffering=0 und error_reporting=E_ALL: admin/ und
intern/ melden keine Header- oder Sessionwarnungen mehr, POSTs ohne Token
liefern 403, mit Token laufen sie durch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-03 15:16:40 +02:00
co-authored by Claude Opus 5
parent 86115b18a7
commit 6d903ac4fc
16 changed files with 38 additions and 26 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
<?php <?php
// WICHTIG: Pfade aus /admin heraus korrekt auflösen // WICHTIG: Pfade aus /admin heraus korrekt auflösen
require_once __DIR__ . "/../inc/config.inc.php"; require_once __DIR__ . "/../inc/config.inc.php";
+1 -1
View File
@@ -1,4 +1,4 @@
<?php <?php
require_once __DIR__ . "/../inc/config.inc.php"; require_once __DIR__ . "/../inc/config.inc.php";
require_once __DIR__ . "/../inc/functions.inc.php"; require_once __DIR__ . "/../inc/functions.inc.php";
+1 -1
View File
@@ -1,3 +1,3 @@
<?php <?php
$_GET['view'] = 'event-create'; $_GET['view'] = 'event-create';
require_once __DIR__ . '/impfworkflow.php'; require_once __DIR__ . '/impfworkflow.php';
+1 -1
View File
@@ -1,3 +1,3 @@
<?php <?php
$_GET['view'] = 'event-teilnehmer'; $_GET['view'] = 'event-teilnehmer';
require_once __DIR__ . '/impfworkflow.php'; require_once __DIR__ . '/impfworkflow.php';
+1 -1
View File
@@ -1,4 +1,4 @@
<?php <?php
require_once __DIR__ . "/../inc/config.inc.php"; require_once __DIR__ . "/../inc/config.inc.php";
require_once __DIR__ . "/../inc/functions.inc.php"; require_once __DIR__ . "/../inc/functions.inc.php";
+1 -1
View File
@@ -1,3 +1,3 @@
<?php <?php
$_GET['view'] = 'teilnehmer'; $_GET['view'] = 'teilnehmer';
require_once __DIR__ . '/impfworkflow.php'; require_once __DIR__ . '/impfworkflow.php';
+1 -1
View File
@@ -1,4 +1,4 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="de"> <html lang="de">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
+1 -1
View File
@@ -1,2 +1,2 @@
<?php <?php
require_once __DIR__ . '/impfbestaetigung.php'; require_once __DIR__ . '/impfbestaetigung.php';
+1 -1
View File
@@ -1,2 +1,2 @@
<?php <?php
require_once __DIR__ . '/impfwarteliste.php'; require_once __DIR__ . '/impfwarteliste.php';
+1 -1
View File
@@ -1,2 +1,2 @@
<?php <?php
require_once __DIR__ . '/impfwarteliste.php'; require_once __DIR__ . '/impfwarteliste.php';
+1 -1
View File
@@ -1,4 +1,4 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<!-- <!--
Alpha by HTML5 UP Alpha by HTML5 UP
html5up.net | @n33co html5up.net | @n33co
+1 -1
View File
@@ -1,2 +1,2 @@
<?php <?php
require_once __DIR__ . '/impfwarteliste.php'; require_once __DIR__ . '/impfwarteliste.php';
+16 -6
View File
@@ -85,13 +85,23 @@ if (session_status() !== PHP_SESSION_ACTIVE) {
session_start(); session_start();
} }
// CSRF-Schutz im Adminbereich: Token in jedes POST-Formular einsetzen und // CSRF-Schutz fuer die angemeldeten Bereiche: Token in jedes POST-Formular
// eingehende POSTs pruefen. Muss nach session_start() und vor jeder // einsetzen und eingehende POSTs pruefen. Muss nach session_start() und vor
// Ausgabe der Seite laufen. // jeder Ausgabe der Seite laufen. Der oeffentliche Bereich bleibt aussen vor,
$adminVerzeichnis = realpath(__DIR__ . '/../admin'); // dort gibt es keine Sitzung, die missbraucht werden koennte.
$geschuetzteBereiche = [
realpath(__DIR__ . '/../admin'),
realpath(__DIR__ . '/../intern'),
];
$laufendesSkript = realpath($_SERVER['SCRIPT_FILENAME'] ?? ''); $laufendesSkript = realpath($_SERVER['SCRIPT_FILENAME'] ?? '');
if ($adminVerzeichnis !== false && $laufendesSkript !== false
&& strncmp($laufendesSkript, $adminVerzeichnis . DIRECTORY_SEPARATOR, strlen($adminVerzeichnis) + 1) === 0) { foreach ($geschuetzteBereiche as $verzeichnis) {
if ($verzeichnis === false || $laufendesSkript === false) {
continue;
}
if (strncmp($laufendesSkript, $verzeichnis . DIRECTORY_SEPARATOR, strlen($verzeichnis) + 1) === 0) {
csrf_autoinject(); csrf_autoinject();
csrf_require(); csrf_require();
break;
}
} }
+1 -1
View File
@@ -75,7 +75,7 @@ function csrf_require(): void
echo '<h3>Die Anfrage wurde abgelehnt.</h3>'; echo '<h3>Die Anfrage wurde abgelehnt.</h3>';
echo 'Das Sicherheitstoken war ungültig oder die Sitzung ist abgelaufen.<br>'; echo 'Das Sicherheitstoken war ungültig oder die Sitzung ist abgelaufen.<br>';
echo 'Bitte die Seite neu laden und den Vorgang wiederholen.<br><br>'; echo 'Bitte die Seite neu laden und den Vorgang wiederholen.<br><br>';
echo '<a href="index.php">Zurück zum Adminbereich</a>'; echo '<a href="index.php">Zurück zur Übersicht</a>';
exit; exit;
} }
+1 -1
View File
@@ -1,4 +1,4 @@
<?php <?php
/** /**
* @package Patientsuche * @package Patientsuche
* @copyright Copyright (C) 2021 ctb-it.de Inc. All rights reserved. * @copyright Copyright (C) 2021 ctb-it.de Inc. All rights reserved.
+5 -3
View File
@@ -7,10 +7,12 @@
ob_start(); ob_start();
require_once(__DIR__ . "/../inc/config.inc.php"); require_once(__DIR__ . "/../inc/config.inc.php");
require_once(__DIR__ . "/../inc/functions.inc.php"); require_once(__DIR__ . "/../inc/functions.inc.php");
session_start();
ini_set('session.gc_maxlifetime', 30*24*60*60); // 30 Tage // Hinweis: hier standen zwei ini_set() auf session.gc_maxlifetime und
ini_set('session.cookie_lifetime', 30*24*60*60); // 30 Tage // session.cookie_lifetime. Beide liefen ins Leere, weil die Sitzung zu
// diesem Zeitpunkt schon laeuft - PHP ignoriert Session-Einstellungen
// dann und meldet eine Warnung. Die Lebensdauer des Cookies kommt aus
// session_set_cookie_params() in inc/config.inc.php (30 Tage).
include(__DIR__ . "/../inc/password.inc.php"); include(__DIR__ . "/../inc/password.inc.php");
$error_msg = ""; $error_msg = "";