Sicherheitsleitfaden

SLAED CMS wird mit Fokus auf Sicherheit entwickelt und beinhaltet ein mehrschichtiges Schutzsystem gegen wichtige Arten von Angriffen und Bedrohungen.

Sicherheitsarchitektur

Sicherheitsprinzipien

  1. Defense in Depth - Mehrschichtiger Schutz
  2. Prinzip der geringsten Rechte - Minimal notwendige Rechte
  3. Eingabevalidierung - Validierung aller Eingabedaten
  4. Ausgabekodierung - Kodierung aller Ausgabedaten
  5. Standardmäßig sicher - Sichere Einstellungen standardmäßig

Hauptkomponenten des Schutzes

┌─────────────────────────────────────────┐
│           SICHERHEITSEBENEN             │
├─────────────────────────────────────────┤
│ 1. Webserver-Sicherheit (Apache/Nginx)  │
│ 2. Anwendungsfirewall                   │
│ 3. Eingabevalidierung & Bereinigung     │
│ 4. Authentifizierung & Autorisierung    │
│ 5. Sitzungsmanagement                   │
│ 6. CSRF-Schutz                          │
│ 7. XSS-Prävention                       │
│ 8. SQL-Injection-Prävention             │
│ 9. Datei-Upload-Sicherheit              │
│ 10. Protokollierung & Überwachung       │
└─────────────────────────────────────────┘

Schutz vor Hauptangriffen

1. SQL-Injection-Schutz

Verwendung von Prepared Statements

// SICHER - Prepared Statements
$stmt = $db->prepare("SELECT * FROM {$prefix}_users WHERE user_id = ? AND active = ?");
$stmt->bind_param("ii", $user_id, $active);
$stmt->execute();
$result = $stmt->get_result();

// UNSICHER - Direkte Ersetzung (NICHT VERWENDEN!)
$query = "SELECT * FROM {$prefix}_users WHERE user_id = " . $user_id;

Automatische Filterung in Kernfunktionen

// getVar-Funktion filtert automatisch Eingabedaten
$id = getVar('get', 'id', 'num');        // Nur Zahlen
$email = getVar('post', 'email', 'email'); // E-Mail-Validierung
$text = getVar('post', 'text', 'text');   // Sicherer Text

2. XSS (Cross-Site Scripting) Schutz

Eingabefilterung

// Automatische Filterung in getVar
function getVar($method, $name, $type, $default = '') {
    switch($type) {
        case 'text':
            return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
        case 'html':
            return filter_html($value);
        case 'var':
            return preg_replace('#[^a-zA-Z0-9_-]#', '', $value);
    }
}

// Zusätzlicher Schutz beim Ausgeben
function xss_clean($str) {
    $str = htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
    $str = preg_replace('#javascript:#i', '', $str);
    $str = preg_replace('#vbscript:#i', '', $str);
    $str = preg_replace('#onload#i', '', $str);
    return $str;
}

Content Security Policy (CSP)

// In Vorlagendateien
header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://www.google.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;");

3. CSRF (Cross-Site Request Forgery) Schutz

Token-Erstellung und Verifizierung

// CSRF-Token erzeugen
function generate_csrf_token() {
    if (!isset($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf_token'];
}

// CSRF-Token verifizieren
function verify_csrf_token($token) {
    if (!isset($_SESSION['csrf_token'])) {
        return false;
    }
    return hash_equals($_SESSION['csrf_token'], $token);
}

// Verwendung in Formularen
echo '<input type="hidden" name="csrf_token" value="'.generate_csrf_token().'">';

// Verifizierung bei der Formularverarbeitung
if (!verify_csrf_token(getVar('post', 'csrf_token', 'text'))) {
    die('CSRF-Token stimmt nicht überein');
}

4. Datei-Upload-Sicherheit

Strenge Datei-Upload-Prüfung

function secure_file_upload($file, $allowed_types, $max_size, $upload_dir) {
    // 1. Dateityp nach Erweiterung prüfen
    $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
    if (!in_array($ext, $allowed_types)) {
        return false;
    }
    
    // 2. MIME-Typ prüfen
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mime = finfo_file($finfo, $file['tmp_name']);
    finfo_close($finfo);
    
    $allowed_mimes = array(
        'jpg' => 'image/jpeg',
        'png' => 'image/png',
        'gif' => 'image/gif',
        'pdf' => 'application/pdf'
    );
    
    if (!isset($allowed_mimes[$ext]) || $allowed_mimes[$ext] !== $mime) {
        return false;
    }
    
    // 3. Größe prüfen
    if ($file['size'] > $max_size) {
        return false;
    }
    
    // 4. Auf ausführbare Dateien prüfen
    $dangerous_extensions = array('php', 'phtml', 'php3', 'php4', 'php5', 'pl', 'py', 'jsp', 'asp', 'sh', 'cgi');
    if (in_array($ext, $dangerous_extensions)) {
        return false;
    }
    
    // 5. Sicheren Dateinamen generieren
    $safe_name = uniqid().'_'.preg_replace('#[^a-zA-Z0-9.-]#', '_', basename($file['name']));
    
    // 6. Datei verschieben
    if (move_uploaded_file($file['tmp_name'], $upload_dir.'/'.$safe_name)) {
        return $safe_name;
    }
    
    return false;
}

Zusätzliche Sicherheitsmaßnahmen

# .htaccess im Uploads-Ordner
<Files "*.php">
    Deny from all
</Files>
<Files "*.phtml">
    Deny from all
</Files>
<Files "*.php3">
    Deny from all
</Files>

Authentifizierung & Autorisierung

Rollen- und Zugriffssystem

// Benutzerhierarchie
define('USER_GUEST', 0);        // Gast
define('USER_MEMBER', 1);       // Benutzer
define('USER_MODERATOR', 2);    // Moderator
define('USER_ADMIN', 3);        // Administrator
define('USER_SUPERADMIN', 4);   // Super-Administrator

// Zugriffsebene prüfen
function check_access_level($required_level, $user_level = null) {
    global $user;
    
    if ($user_level === null) {
        $user_level = isset($user[3]) ? intval($user[3]) : USER_GUEST;
    }
    
    return $user_level >= $required_level;
}

// Modul-Admin prüfen
function is_module_admin($module) {
    global $db, $prefix, $user;
    
    if (!is_user()) return false;
    if (is_admin()) return true;
    
    $user_id = intval($user[0]);
    $stmt = $db->prepare("SELECT COUNT(*) FROM {$prefix}_module_admins WHERE user_id = ? AND module = ?");
    $stmt->bind_param("is", $user_id, $module);
    $stmt->execute();
    $result = $stmt->get_result();
    $count = $result->fetch_row()[0];
    
    return $count > 0;
}

Sichere Authentifizierung

// Passwort-Hashing
function hash_password($password) {
    return password_hash($password, PASSWORD_ARGON2ID, [
        'memory_cost' => 65536,  // 64MB
        'time_cost' => 4,        // 4 Iterationen
        'threads' => 3,          // 3 Threads
    ]);
}

// Passwort-Verifizierung
function verify_password($password, $hash) {
    return password_verify($password, $hash);
}

// Passwort-Stärke prüfen
function check_password_strength($password) {
    $strength = 0;
    
    if (strlen($password) >= 8) $strength++;
    if (preg_match('/[a-z]/', $password)) $strength++;
    if (preg_match('/[A-Z]/', $password)) $strength++;
    if (preg_match('/[0-9]/', $password)) $strength++;
    if (preg_match('/[^a-zA-Z0-9]/', $password)) $strength++;
    
    return $strength; // 0-5
}

Sitzungsmanagement

// Sichere Sitzungseinstellungen
function init_secure_session() {
    // Sitzungs-Cookie-Einstellungen
    $cookie_params = array(
        'lifetime' => 0,
        'path' => '/',
        'domain' => '',
        'secure' => isset($_SERVER['HTTPS']),
        'httponly' => true,
        'samesite' => 'Strict'
    );
    
    session_set_cookie_params($cookie_params);
    
    // Sitzungs-ID neu generieren
    if (!isset($_SESSION['initiated'])) {
        session_regenerate_id(true);
        $_SESSION['initiated'] = true;
    }
    
    // IP-Adresse und User-Agent prüfen
    if (isset($_SESSION['user_ip']) && $_SESSION['user_ip'] !== getIp()) {
        session_destroy();
        return false;
    }
    
    if (isset($_SESSION['user_agent']) && $_SESSION['user_agent'] !== getUserAgent()) {
        session_destroy();
        return false;
    }
    
    $_SESSION['user_ip'] = getIp();
    $_SESSION['user_agent'] = getUserAgent();
    
    return true;
}

// Sichere Sitzungsbeendigung
function secure_logout() {
    $_SESSION = array();
    
    if (ini_get("session.use_cookies")) {
        $params = session_get_cookie_params();
        setcookie(session_name(), '', time() - 42000,
            $params["path"], $params["domain"],
            $params["secure"], $params["httponly"]
        );
    }
    
    session_destroy();
}

Schutz vor automatisierten Angriffen

Rate Limiting / Flood-Schutz

// Flood-Schutz
function check_flood_protection($action, $ip = null, $user_id = null) {
    global $db, $prefix, $confs;
    
    if (!$confs['flood_enable']) return true;
    
    $ip = $ip ?: getIp();
    $user_id = $user_id ?: (is_user() ? intval($user[0]) : 0);
    $time_limit = time() - intval($confs['flood_time']);
    
    // Versuche zählen
    $stmt = $db->prepare("SELECT COUNT(*) FROM {$prefix}_flood_log WHERE action = ? AND (ip = ? OR user_id = ?) AND timestamp > ?");
    $stmt->bind_param("ssii", $action, $ip, $user_id, $time_limit);
    $stmt->execute();
    $attempts = $stmt->get_result()->fetch_row()[0];
    
    if ($attempts >= intval($confs['flood_attempts'])) {
        // Versuch protokollieren
        log_security_event('FLOOD_DETECTED', array(
            'action' => $action,
            'ip' => $ip,
            'user_id' => $user_id,
            'attempts' => $attempts
        ));
        
        return false;
    }
    
    // Versuch aufzeichnen
    $stmt = $db->prepare("INSERT INTO {$prefix}_flood_log (action, ip, user_id, timestamp) VALUES (?, ?, ?, ?)");
    $current_time = time();
    $stmt->bind_param("ssii", $action, $ip, $user_id, $current_time);
    $stmt->execute();
    
    return true;
}

CAPTCHA-Integration

// Google reCAPTCHA v3
function verify_recaptcha_v3($response, $action = 'homepage') {
    global $confs;
    
    if (!$confs['captcha_enable']) return true;
    
    $secret_key = $confs['recaptcha_secret_key'];
    $verify_url = 'https://www.google.com/recaptcha/api/siteverify';
    
    $data = array(
        'secret' => $secret_key,
        'response' => $response,
        'remoteip' => getIp()
    );
    
    $options = array(
        'http' => array(
            'header' => "Content-type: application/x-www-form-urlencoded\r\n",
            'method' => 'POST',
            'content' => http_build_query($data)
        )
    );
    
    $context = stream_context_create($options);
    $result = file_get_contents($verify_url, false, $context);
    $response_data = json_decode($result, true);
    
    if ($response_data['success'] && 
        $response_data['action'] === $action && 
        $response_data['score'] >= floatval($confs['recaptcha_score'])) {
        return true;
    }
    
    log_security_event('CAPTCHA_FAILED', array(
        'ip' => getIp(),
        'score' => $response_data['score'] ?? 0,
        'action' => $action
    ));
    
    return false;
}

Sicherheitsüberwachung & Protokollierung

Protokollierungssystem

// Sicherheitsereignisse protokollieren
function log_security_event($event_type, $data = array()) {
    global $user;
    
    $log_entry = array(
        'timestamp' => date('Y-m-d H:i:s'),
        'event_type' => $event_type,
        'ip' => getIp(),
        'user_agent' => getUserAgent(),
        'user_id' => is_user() ? intval($user[0]) : 0,
        'data' => $data
    );
    
    $log_line = json_encode($log_entry) . "\n";
    file_put_contents(LOGS_DIR.'/security.log', $log_line, FILE_APPEND | LOCK_EX);
    
    // Kritische Ereignisse
    if (in_array($event_type, array('ADMIN_LOGIN_FAILED', 'SQL_INJECTION_ATTEMPT', 'XSS_ATTEMPT'))) {
        send_security_alert($event_type, $log_entry);
    }
}

// Alarme für kritische Ereignisse senden
function send_security_alert($event_type, $log_entry) {
    global $conf;
    
    $subject = 'Sicherheitsalarm: ' . $event_type;
    $message = "Sicherheitsereignis erkannt:\n\n";
    $message .= "Typ: " . $event_type . "\n";
    $message .= "Zeit: " . $log_entry['timestamp'] . "\n";
    $message .= "IP: " . $log_entry['ip'] . "\n";
    $message .= "User Agent: " . $log_entry['user_agent'] . "\n";
    $message .= "Details: " . json_encode($log_entry['data'], JSON_PRETTY_PRINT);
    
    mail($conf['admin_email'], $subject, $message);
}

Überwachung verdächtiger Aktivitäten

// Verdächtige Muster analysieren
function analyze_suspicious_activity($ip) {
    global $db, $prefix;
    
    $suspicious_score = 0;
    $last_hour = time() - 3600;
    
    // Häufige fehlgeschlagene Login-Versuche
    $stmt = $db->prepare("SELECT COUNT(*) FROM {$prefix}_login_attempts WHERE ip = ? AND success = 0 AND timestamp > ?");
    $stmt->bind_param("si", $ip, $last_hour);
    $stmt->execute();
    $failed_logins = $stmt->get_result()->fetch_row()[0];
    
    if ($failed_logins > 10) $suspicious_score += 3;
    elseif ($failed_logins > 5) $suspicious_score += 2;
    elseif ($failed_logins > 3) $suspicious_score += 1;
    
    // Häufige Anfragen an nicht existente Seiten
    $stmt = $db->prepare("SELECT COUNT(*) FROM {$prefix}_404_log WHERE ip = ? AND timestamp > ?");
    $stmt->bind_param("si", $ip, $last_hour);
    $stmt->execute();
    $not_found_requests = $stmt->get_result()->fetch_row()[0];
    
    if ($not_found_requests > 20) $suspicious_score += 2;
    elseif ($not_found_requests > 10) $suspicious_score += 1;
    
    // SQL-Injection-Versuche
    $stmt = $db->prepare("SELECT COUNT(*) FROM {$prefix}_security_log WHERE ip = ? AND event_type = 'SQL_INJECTION_ATTEMPT' AND timestamp > ?");
    $stmt->bind_param("si", $ip, $last_hour);
    $stmt->execute();
    $sql_attempts = $stmt->get_result()->fetch_row()[0];
    
    if ($sql_attempts > 0) $suspicious_score += 5;
    
    // Automatische Blockierung bei hohem Verdachtswert
    if ($suspicious_score >= 5) {
        block_ip($ip, 'Verdächtige Aktivität erkannt');
        log_security_event('IP_AUTO_BLOCKED', array('ip' => $ip, 'score' => $suspicious_score));
    }
    
    return $suspicious_score;
}

Konfigurationssicherheit

Konfigurationsdateien schützen

# .htaccess zum Schutz des config-Ordners
<Files "*.php">
    Order Deny,Allow
    Deny from all
    Allow from 127.0.0.1
</Files>

<Files "*.txt">
    Order Deny,Allow
    Deny from all
</Files>

<Files "*.log">
    Order Deny,Allow
    Deny from all
</Files>

Sichere Dateiberechtigungen

# Richtige Dateiberechtigungen setzen
find /path/to/slaed/ -type f -exec chmod 644 {} \;
find /path/to/slaed/ -type d -exec chmod 755 {} \;

# Spezielle Berechtigungen für kritische Ordner
chmod 700 /path/to/slaed/config/
chmod 777 /path/to/slaed/uploads/
chmod 777 /path/to/slaed/storage/

# Ausführung im Uploads-Ordner deaktivieren
chmod -x /path/to/slaed/uploads/*

Sicherheitsempfehlungen

Regelmäßige Sicherheitsprüfungen

  1. Protokollprüfung - Tägliche Analyse der Sicherheitsprotokolle
  2. Updates - Zeitnahe PHP-, MySQL-, Webserver-Updates
  3. Überwachung - Kontrolle verdächtiger Aktivitäten
  4. Backups - Regelmäßige Sicherung
  5. Tests - Periodische Penetrationstests

Sicherheits-Checkliste

  • PHP auf neueste Version aktualisiert
  • Neueste Sicherheitsupdates installiert
  • Webserver-Firewall konfiguriert
  • HTTPS/SSL aktiviert
  • Sichere HTTP-Header konfiguriert
  • Unbenutzte PHP-Module und Funktionen deaktiviert
  • Sicherheitsprotokollierung konfiguriert
  • Überwachungslösungen eingerichtet
  • Verwundbarkeitstests durchgeführt
  • Automatische Backups konfiguriert

Durch das Befolgen dieser Empfehlungen und die Nutzung der integrierten Schutzmechanismen von SLAED CMS gewährleisten Sie ein hohes Sicherheitsniveau für Ihre Website.