Sicherheit

Sicherheit ist kein optionales Feature — sie gehört von Anfang an in jedes Modul. Die häufigsten Angriffsvektoren und wie man sie verhindert.


Guard in jeder Datei

Die erste Zeile nach <?php in jeder Modul-Datei:

defined('WB_PATH') or die("This file cannot be accessed directly!");

Verhindert den direkten Aufruf der Datei über den Browser.

Ausnahme: Dateien die direkt aufgerufen werden müssen (save.php, download.php) brauchen stattdessen einen Auth-Check:

require('../../config.php');
defined('WB_PATH') or die("This file cannot be accessed directly!");
require_once(WB_PATH . '/framework/class.admin.php');
$admin = new admin('Pages', 'modify', false, false);

CSRF-Schutz (FTAN)

Formulare müssen mit einem FTAN-Token geschützt werden:

In modify.php (Formular ausgeben):

<form action="..." method="post">
    <?php echo $admin->getFTAN(); ?>
    ...
</form>

In save.php (Token prüfen):

if (!$admin->checkFTAN()) {
    $admin->print_error('Ungültige Anfrage.');
    exit;
}

Für GET-Links (z.B. Löschen-Button):

<a href="delete.php?<?php echo $admin->getFTAN(false); ?>&id=<?php echo $id; ?>">Löschen</a>

// In delete.php:
if (!$admin->checkFTAN('GET')) {
    $admin->print_error('Ungültige Anfrage.');
    exit;
}

SQL-Injection verhindern

Immer escapen oder Parameter-Binding nutzen:

// Einfacher Weg — escapeString:
$text = $database->escapeString($_POST['text'] ?? '');
$database->query("UPDATE ... SET text='$text' WHERE ...");

// Besserer Weg — Parameter-Binding (neue PDO-Klasse):
$database->query(
    "UPDATE `{TP}mod_mein_modul` SET `text` = ? WHERE `section_id` = ?",
    [$text, $section_id]
);

XSS verhindern

Ausgaben immer escapen:

// Bei der Ausgabe im HTML:
echo htmlspecialchars($text, ENT_QUOTES, 'UTF-8');

// Für Attribute:
echo htmlspecialchars($value, ENT_QUOTES, 'UTF-8');

// HTML erlauben aber bereinigen:
// → Nur vertrauenswürdige Inhalte direkt ausgeben!
echo $html_content; // Nur wenn Inhalt aus DB kommt, nicht aus User-Input

Datei-Uploads absichern

// Erlaubte Dateitypen definieren
$allowed = ['jpg', 'png', 'pdf'];
$ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));

if (!in_array($ext, $allowed)) {
    $admin->print_error('Dateityp nicht erlaubt.');
    exit;
}

// MIME-Typ prüfen
if (function_exists('finfo_open')) {
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mime  = finfo_file($finfo, $_FILES['file']['tmp_name']);
    finfo_close($finfo);
    // Erlaubte MIME-Typen prüfen...
}

// Nur Admins dürfen hochladen
if (!$admin->isAdmin()) {
    $admin->print_error('Keine Berechtigung.');
    exit;
}

Path Traversal verhindern

$base = realpath(WB_PATH . MEDIA_DIRECTORY . '/uploads');
$name = basename($filename);
$real = realpath($base . DIRECTORY_SEPARATOR . $name);

if (!$real || strncmp($real, $base . DIRECTORY_SEPARATOR, strlen($base) + 1) !== 0) {
    die("Zugriff verweigert.");
}

PRG-Pattern (Post/Redirect/Get)

Nach dem Speichern immer weiterleiten — verhindert Doppel-Submit:

// Am Ende von save.php:
header('Location: ' . ADMIN_URL . '/pages/modify.php?page_id=' . $page_id);
exit;

Checkliste

✅ Guard in jeder Datei
✅ FTAN in allen Formularen
✅ Eingaben escapen vor DB
✅ Ausgaben escapen mit htmlspecialchars
✅ Datei-Uploads auf Typ + MIME prüfen
✅ Path Traversal prüfen
✅ PRG-Pattern nach Speichern
✅ isAdmin() für sensitive Aktionen

Gut gemacht — dein Modul ist jetzt sicher! 🦩