aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Metin2

Metin2 Register-System: ein sicheres PHP-Anmeldeformular

Wenn du einen Metin2-Server startest, ist die erste Tür, durch die Spieler gehen, das Anmeldeformular auf deiner Website. Ein gut gebautes Metin2 Register-System macht mehr, als nur einen Benutzernamen und ein Passwort entgegenzunehmen; es validiert Eingaben, speichert das Passwort genau in dem Format, das das Spiel erwartet, und schreibt sicher in die account-Tabelle. In dieser Anleitung bauen wir von Grund auf einen funktionierenden, injektionssicheren Registrierungsablauf mit PHP und PDO.

Wie die account-Tabelle funktioniert

In klassischen Metin2-Quellen liegen die Mitgliedsdaten in der account-Tabelle innerhalb einer Datenbank namens account. Der Spielkern (die game- und db-Prozesse) authentifiziert Logins direkt gegen diese Tabelle. Die Spalten, die uns interessieren, sind:

  • login — der Benutzername (meist kurz und eindeutig).
  • password — das Feld, das das Spiel liest. Die klassische Quelle erwartet den 41-Zeichen-Hash, den die PASSWORD()-Funktion von MySQL erzeugt.
  • social_id — ein 7-stelliger Sicherheitscode (ein zweites Passwort), der für Aktionen wie das Löschen von Charakteren verwendet wird.
  • email und create_time — Kontaktdaten und Registrierungszeit.

Ein entscheidendes Detail: Die PASSWORD()-Funktion wurde in MySQL 8.0 entfernt. Die meisten Metin2-Server laufen unter MariaDB oder MySQL 5.x, daher existiert die Funktion noch, aber du musst deine Version prüfen. Du bist gezwungen, das Passwort mit demselben Algorithmus zu speichern, den der Spielkern verwendet — sonst kann ein Spieler, der sich im Web registriert, nicht ins Spiel einloggen.

Eine sichere Datenbankverbindung

Verwende vor allem PDO mit Prepared Statements. Indem du die Benutzereingabe von der Abfrage trennst, stoppst du SQL-Injection an der Wurzel. Halte die Verbindung in einer separaten config.php-Datei:

<?php
// config.php
$host = '127.0.0.1';
$db   = 'account';
$user = 'metin2_web';      // Benutzer mit Rechten nur auf der account-Tabelle
$pass = 'STARKES_PASSWORT';

$dsn = "mysql:host=$host;dbname=$db;charset=utf8mb4";
$pdo = new PDO($dsn, $user, $pass, [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES   => false,
]);

Erstelle einen dedizierten MySQL-Benutzer für das Web und gewähre ihm nur die Rechte, die er auf account.account braucht. Selbst wenn der Webserver kompromittiert wird, soll der Angreifer nicht an deine gesamte Spieldatenbank gelangen.

Das Anmeldeformular und die Eingabevalidierung

Beginne mit einem einfachen, aber ausreichenden HTML-Formular. Die eigentliche Arbeit ist die Validierung der eingehenden Daten auf der Serverseite — vertraue niemals Prüfungen auf der Clientseite.

<form method="post" action="register.php">
  <input name="login" placeholder="Benutzername" required>
  <input name="email" type="email" placeholder="E-Mail" required>
  <input name="password" type="password" placeholder="Passwort" required>
  <input name="password2" type="password" placeholder="Passwort wiederholen" required>
  <input type="hidden" name="csrf" value="<?= $_SESSION['csrf'] ?>">
  <button type="submit">Registrieren</button>
</form>

Prüfe auf der Serverseite jedes Feld einzeln:

<?php
session_start();
require 'config.php';

// CSRF-Prüfung
if (!hash_equals($_SESSION['csrf'] ?? '', $_POST['csrf'] ?? '')) {
    http_response_code(400);
    exit('Ungültige Anfrage.');
}

$login = trim($_POST['login'] ?? '');
$email = trim($_POST['email'] ?? '');
$pw    = $_POST['password'] ?? '';
$pw2   = $_POST['password2'] ?? '';
$errors = [];

if (!preg_match('/^[a-zA-Z0-9]{4,16}$/', $login)) {
    $errors[] = 'Benutzername muss 4-16 Buchstaben/Ziffern sein.';
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $errors[] = 'Gib eine gültige E-Mail ein.';
}
if (strlen($pw) < 6 || $pw !== $pw2) {
    $errors[] = 'Passwort muss mindestens 6 Zeichen haben und beide Felder müssen übereinstimmen.';
}

Das Feld login auf ein striktes Muster zu beschränken (nur Buchstaben und Ziffern) verhindert sowohl Kompatibilitätsprobleme mit dem Spielclient als auch unerwartete Zeichen.

Auf Benutzernamen-Kollisionen prüfen

Um zu verhindern, dass sich zwei Personen mit demselben Benutzernamen registrieren, frage vor dem Schreiben ab. Verwende auch hier ein Prepared Statement:

if (!$errors) {
    $stmt = $pdo->prepare('SELECT id FROM account WHERE login = ? LIMIT 1');
    $stmt->execute([$login]);
    if ($stmt->fetch()) {
        $errors[] = 'Dieser Benutzername ist bereits vergeben.';
    }
}

Mach das trotzdem nicht zu deiner einzigen Verteidigungslinie: Füge einen UNIQUE-Index auf der Spalte login der account-Tabelle hinzu. Wenn zwei Anfragen im selben Moment eintreffen, blockiert die Einschränkung auf Datenbankebene das Duplikat.

Passwort hashen und in die account-Tabelle schreiben

Im letzten Schritt erstellen wir den Datensatz. Das Passwort innerhalb des SQL mit PASSWORD() zu hashen, garantiert das vom Spiel erwartete Format. Erzeuge einen zufälligen 7-stelligen Code für social_id:

if (!$errors) {
    $social = sprintf('%07d', random_int(0, 9999999));

    $sql = 'INSERT INTO account (login, password, social_id, email, create_time)
            VALUES (?, PASSWORD(?), ?, ?, NOW())';
    $stmt = $pdo->prepare($sql);
    $stmt->execute([$login, $pw, $social, $email]);

    header('Location: register.php?ok=1');
    exit;
}

Beachte, dass wir das Klartext-Passwort als Parameter übergeben und MySQL das Hashen erledigen lassen. So bleibt die Sicherheit der Prepared Statements erhalten, während der Hash Byte für Byte mit dem Spiel kompatibel ist. Wenn du das Passwort selbst in PHP hasht (etwa mit password_hash()) und das speicherst, erkennt der Spielkern es nicht — ein sehr häufiger Fehler. password_hash()/bcrypt ist nur sinnvoll, wenn du ein rein webbasiertes Account-System baust, das unabhängig vom Spiel ist.

Vor dem Produktivbetrieb

Sobald der Ablauf funktioniert, füge diese Sicherheitsschichten hinzu:

  • Rate-Limiting: Blockiere mehr als ein paar Registrierungen pro Minute von derselben IP, um Bots auszubremsen.
  • HTTPS erzwingen: Passwörter dürfen niemals im Klartext übertragen werden.
  • CAPTCHA: Füge hCaptcha/reCAPTCHA gegen automatisierte Anmeldungen hinzu.
  • Fehler maskieren: Zeige dem Benutzer niemals technische Fehler; logge Details auf der Serverseite.

Häufige Fragen

Warum das Passwort in MySQL statt in PHP hashen?

Weil der Metin2-Spielkern das Login-Passwort mit dem Hash vergleicht, den die PASSWORD()-Funktion von MySQL erzeugt. Wenn du nicht denselben Algorithmus verwendest, kann ein Spieler, der sich im Web registriert, das Spiel nicht betreten. Sofern Web und Spiel keine getrennten Systeme sind, ist die Übereinstimmung Pflicht.

Was, wenn mein Server die PASSWORD()-Funktion nicht hat?

MySQL 8.0 hat sie entfernt. Die Lösung ist der Wechsel zu MariaDB oder MySQL 5.7 (das die meisten Metin2-Installationen ohnehin verwenden) oder das Abbilden des Hashes, den dein Kern unterstützt (manche Forks liefern modifizierte Schemata). In jedem Fall ist die Referenz der Auth-Code deines Spielkerns.

Wofür ist social_id, kann ich es leer lassen?

social_id ist der Sicherheitscode im Spiel (ein zweites Passwort), der bei kritischen Aktionen wie dem Löschen eines Charakters abgefragt wird. Statt es leer zu lassen, ist der sicherste Ansatz, bei der Registrierung einen Zufallswert zuzuweisen und den Spieler ihn über sein Panel ändern zu lassen.

Brauchst du eine sichere Registrierung und ein Account-Panel für deinen Metin2-Server? Ich kann es von Anfang bis Ende mit Validierung, E-Mail-Bestätigung und Panel-Integration bauen — kontaktiere mich.

Bu kategorideki tüm yazılar →

Devamı için