Security: OAuth-state, Verschlüsselung, Session-Timeout & weitere Härtung

- m365_callback.php: OAuth-state-Validierung gegen Login-CSRF
- includes/Crypto.php: Verschlüsselung-at-rest für UniFi-Passwörter
  (AES-256-GCM/libsodium) mit Klartext-Fallback für Bestandsinstallationen
- install.php: APP_KEY-Generierung + Reinstall nur mit Admin-Session
- Auth.php: absolutes Session-Timeout (SESSION_LIFETIME) durchsetzen
- index.php: CSRF + Throttle auch für anonyme öffentliche Voucher-Erstellung
- UniFiController.php: createVoucher liefert nicht mehr den falschen Code
  bei parallelen Erstellungen (note-Match statt blindes reset())
- display_errors in allen Entry-Points deaktiviert, log_errors aktiviert
- test.php & m365_debug.php hinter requireAdmin() (Info-Leak)
- m365_debug.php: abgeschnittene/kaputte Datei vervollständigt
This commit is contained in:
Claude 2026-06-05 18:45:47 +00:00
parent bf3e55a967
commit 3483da274f
No known key found for this signature in database
17 changed files with 306 additions and 36 deletions

View file

@ -1,6 +1,7 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
require_once __DIR__ . '/../config.php';
require_once __DIR__ . '/../includes/Database.php';
@ -37,7 +38,7 @@ if (isset($_GET['ajax_stats'])) {
$controller = new UniFiController(
$site['unifi_controller_url'],
$site['unifi_username'],
$site['unifi_password'],
Crypto::decrypt($site['unifi_password']),
$site['site_id']
);
$controller->syncVouchersToDatabase($db, $site['id']);

View file

@ -1,6 +1,7 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
require_once __DIR__ . '/../config.php';
require_once __DIR__ . '/../includes/Database.php';

View file

@ -1,6 +1,7 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
require_once __DIR__ . '/../config.php';
require_once __DIR__ . '/../includes/Database.php';
@ -44,7 +45,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['edit_site'])) {
// Mit neuem Passwort aktualisieren
$db->execute(
"UPDATE sites SET name = ?, site_id = ?, unifi_controller_url = ?, unifi_username = ?, unifi_password = ?, public_access = ? WHERE id = ?",
[$name, $siteIdStr, $controllerUrl, $username, $password, $publicAccess, $siteId]
[$name, $siteIdStr, $controllerUrl, $username, Crypto::encrypt($password), $publicAccess, $siteId]
);
} else {
// Ohne Passwort-Änderung
@ -88,7 +89,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_site'])) {
$db->execute(
"INSERT INTO sites (name, site_id, unifi_controller_url, unifi_username, unifi_password, public_access)
VALUES (?, ?, ?, ?, ?, ?)",
[$name, $siteId, $controllerUrl, $username, $password, $publicAccess]
[$name, $siteId, $controllerUrl, $username, Crypto::encrypt($password), $publicAccess]
);
$success = 'Site erfolgreich hinzugefügt!';

View file

@ -1,6 +1,7 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
require_once __DIR__ . '/../config.php';
require_once __DIR__ . '/../includes/Database.php';

View file

@ -1,6 +1,7 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
require_once __DIR__ . '/../config.php';
require_once __DIR__ . '/../includes/Database.php';
@ -68,7 +69,7 @@ if (isset($_GET['ajax_get_vouchers']) && isset($_GET['site_id'])) {
$controller = new UniFiController(
$site['unifi_controller_url'],
$site['unifi_username'],
$site['unifi_password'],
Crypto::decrypt($site['unifi_password']),
$site['site_id']
);
$controller->syncVouchersToDatabase($db, $siteId);
@ -149,7 +150,7 @@ if (isset($_POST['ajax_delete']) && isset($_POST['voucher_id']) && isset($_POST[
$controller = new UniFiController(
$site['unifi_controller_url'],
$site['unifi_username'],
$site['unifi_password'],
Crypto::decrypt($site['unifi_password']),
$site['site_id']
);