⚡ TL;DR – Das Wichtigste in 30 Sekunden

Das Experiment: „Schreibe mir ein PHP-Login-System"

KI-Tools wie ChatGPT sind beeindruckend. In Sekunden generieren sie funktionierenden Code. Doch „funktioniert" und „ist sicher" sind zwei verschiedene Dinge – besonders wenn es um Login-Systeme geht, die Ihre Kundendaten schützen sollen.

Ich habe ChatGPT folgende Aufgabe gegeben: „Erstelle ein PHP-Login-System mit Datenbankanbindung." Das Ergebnis habe ich mit meinem professionellen Ansatz verglichen. Die Unterschiede sind erschreckend.

Runde 1: Die Datenbankverbindung

🤖 KI-generiert db.php
$conn = mysqli_connect(
    "localhost",
    "root",          // ⚠ Root-User!
    "",              // ⚠ Kein Passwort!
    "login_db"
);

if (!$conn) {
    die("Verbindung fehlgeschlagen: "
        . mysqli_connect_error());
        // ⚠ Fehlerdetails dem User zeigen!
}
👨‍💻 Senior-Entwickler Database.php
class Database {
    private static ?PDO $pdo = null;

    public static function connect(): PDO
    {
        if (self::$pdo === null) {
            self::$pdo = new PDO(
                "mysql:host=".getenv('DB_HOST'),
                getenv('DB_USER'),
                getenv('DB_PASS'),
                [
                  PDO::ATTR_ERRMODE
                    => PDO::ERRMODE_EXCEPTION,
                  PDO::ATTR_EMULATE_PREPARES
                    => false,
                ]
            );
        }
        return self::$pdo;
    }
}

🚨 Sicherheitsproblem Nr. 1: Datenbankzugang

Die KI verwendet Root-Zugangsdaten ohne Passwort direkt im Quellcode. In Produktion bedeutet das: Jeder, der Zugriff auf den Code erhält, hat vollen Datenbankzugriff. Außerdem gibt die() dem Angreifer technische Details preis, die ihm beim Ausnutzen weiterer Schwachstellen helfen.

✅ Professioneller Ansatz

Der Senior-Entwickler nutzt Umgebungsvariablen (keine Zugangsdaten im Code), PDO mit echten Prepared Statements (ATTR_EMULATE_PREPARES = false), und das Singleton-Pattern für effiziente Verbindungsverwaltung. Fehlermeldungen gehen ins Log – nie zum User.

Runde 2: Das Login-Formular

🤖 KI-generiert login.php
// ⚠ Kein CSRF-Token!
// ⚠ Kein Rate Limiting!

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    $user = $_POST['username'];
    $pass = $_POST['password'];
    // ⚠ Keine Input-Validierung!

    $sql = "SELECT * FROM users
        WHERE username='$user'";
    // ⚠ SQL INJECTION! Kritisch!

    $result = mysqli_query($conn, $sql);
    $row = mysqli_fetch_assoc($result);

    if ($row && $row['password'] == $pass) {
        // ⚠ Klartext-Passwort-Vergleich!
        $_SESSION['user'] = $row['username'];
        header("Location: dashboard.php");
    } else {
        echo "Falsches Passwort!";
        // ⚠ Verrät, dass User existiert
    }
}
👨‍💻 Senior-Entwickler LoginController.php
public function login(Request $req): void
{
    // CSRF-Schutz prüfen
    if (!Token::verify($req->post('csrf'))) {
        throw new SecurityException();
    }

    // Rate Limiting: max 5 Versuche
    if (RateLimit::exceeded($req->ip(), 5)) {
        Response::tooMany(900);
        return;
    }

    // Input validieren & sanitizen
    $email = filter_var(
        $req->post('email'),
        FILTER_VALIDATE_EMAIL
    );

    // Prepared Statement (SQL-sicher)
    $stmt = $this->db->prepare(
        "SELECT id, password_hash
         FROM users WHERE email = ?"
    );
    $stmt->execute([$email]);
    $user = $stmt->fetch();

    // Bcrypt-Vergleich (timing-safe)
    if (!$user || !password_verify(
        $req->post('password'),
        $user['password_hash']
    )) {
        // Gleiche Meldung für beides!
        Flash::error(
            'Zugangsdaten ungültig.'
        );
        return;
    }

    // Session sicher starten
    session_regenerate_id(true);
    $_SESSION['uid'] = $user['id'];
    $_SESSION['ip']  = $req->ip();
}

Die kritischen Unterschiede im Überblick

Sicherheitsmaßnahme 🤖 KI-Code 👨‍💻 Senior
SQL Injection Schutz ✗ Nicht vorhanden ✓ Prepared Statements
CSRF-Token ✗ Fehlt komplett ✓ Bei jedem Request
Passwort-Hashing ✗ Klartext-Vergleich ✓ bcrypt + password_verify()
Rate Limiting ✗ Unbegrenzte Versuche ✓ Max. 5 pro IP/15 Min.
Session-Fixation-Schutz ✗ Keine Session-Regeneration ✓ session_regenerate_id()
User-Enumeration-Schutz ✗ „Falsches Passwort!" ✓ Generische Fehlermeldung
Input-Validierung ✗ Rohdaten aus $_POST ✓ filter_var + Whitelist
Zugangsdaten im Code ✗ Root ohne Passwort ✓ Umgebungsvariablen
Fehlerbehandlung ✗ die() mit Details ✓ Logging + generische Meldung

Warum ist das so gefährlich?

Stellen Sie sich vor: Ein Unternehmer lässt sich von ChatGPT ein Login-System generieren und stellt es online. Der Code „funktioniert" – Benutzer können sich einloggen. Aber:

🚨 Reales Angriffsszenario

Ein Angreifer gibt im Benutzername-Feld folgendes ein:

' OR '1'='1' --

Ergebnis: Sofortiger Zugang als erster Benutzer in der Datenbank – ohne Passwort. Bei einem CRM-System bedeutet das Zugriff auf alle Kundendaten, Verträge und Geschäftsinformationen. Ein Verstoß gegen die DSGVO, der Sie als Unternehmer persönlich treffen kann.

Runde 3: Die Session-Konfiguration

Ein Detail, das die KI fast nie beachtet – aber entscheidend für die Sicherheit ist:

🤖 KI-generiert session.php
session_start();
// Das war's. Keine Konfiguration.
// Standard PHP-Einstellungen.
// ⚠ Cookies ohne Secure-Flag
// ⚠ Cookies ohne HttpOnly
// ⚠ Kein SameSite-Attribut
// ⚠ Schwacher Session-Name
👨‍💻 Senior-Entwickler session.php
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure',   1);
ini_set('session.cookie_samesite','Strict');
ini_set('session.use_strict_mode', 1);
ini_set('session.use_only_cookies',1);
ini_set('session.gc_maxlifetime', 1800);

session_name('__Host-SSID');
session_start();

// Session-Timeout prüfen
if (isset($_SESSION['last'])
    && time() - $_SESSION['last'] > 1800
) {
    session_destroy();
    header('Location: /login');
    exit;
}
$_SESSION['last'] = time();

✅ Warum das wichtig ist

Ohne HttpOnly kann JavaScript den Session-Cookie auslesen (XSS-Angriff). Ohne Secure wird der Cookie über unsichere HTTP-Verbindungen gesendet. Ohne SameSite ist CSRF möglich. Der professionelle Code schützt vor all dem – die KI denkt nicht einmal daran.

Mein Fazit: KI ist ein Werkzeug, kein Entwickler

KI-generierter Code ist ein guter Startpunkt – nicht mehr. Er zeigt die grundlegende Logik, aber vergisst systematisch die Absicherung. Das ist kein Zufall: Die KI wurde auf Millionen von Tutorial-Code trainiert, und Tutorials zeigen selten die vollständige Sicherheitsarchitektur.

Für eine private Spielwiese mag das reichen. Für ein CRM-System, das Kundendaten Ihres Unternehmens verwaltet? Fahrlässig.

Ein erfahrener Entwickler bringt das mit, was keine KI ersetzen kann:

Brauchen Sie ein sicheres System?

Ich entwickle DSGVO-konforme CRM-Systeme und Web-Apps mit professioneller Sicherheitsarchitektur. Lassen Sie uns über Ihr Projekt sprechen.

Kostenloses Erstgespräch vereinbaren →

Haben Sie Fragen zur Sicherheit Ihrer bestehenden Software? Schreiben Sie mir an kontakt@milnersoftware.de – ich schaue mir Ihren Code gerne unverbindlich an.