Brauche Hilfe für sicheres Login-Formular in PHP - ohne Framework

TheShadow12

Praktikant
Beiträge
7
Likes
8
Punkte
3
Hey Leute,

ich bin grad dabei, ein Login-Formular in PHP zu basteln, aber ohne so fancy Frameworks. Will das Ganze irgendwie sicher hinkriegen, aber bin mir nicht sicher, ob ich das grad richtig mache.

Hier ist mein Basic-Code:

Code:
$username = $_POST['username'];
$password = $_POST['password'];

$query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
$result = mysqli_query($conn, $query);

Könnt ihr mir sagen, ob das sicher ist oder was ich besser machen kann?

Danke schon mal für eure Tipps!
 
Beste Antwort
Hallo,

also den Code, den du da gebastelt hast, solltest du so auf keinen Fall mehr verwenden.
Warum nutzt du überhaupt mysqli? Das ist schon lange nicht mehr der Stand der Zeit.

Erstmal würde ich dir empfehlen, dich in PDO (PHP Data Objects) einzuarbeiten. Damit ist dein Code, deine Datenbankabfragen, von Haus aus sicherer, vorausgesetzt du nutzt Prepared Statements - was du unbedingt tun solltest, insbesondere bei Daten die vom Nutzer kommen.

Schau dir dazu gerne mal den Link hier an, dort wird das recht gut erklärt: https://www.php-einfach.de/mysql-tutorial/crashkurs-pdo/

Generell gilt: Traue niemals Daten, die vom Benutzer kommen.

Aus deiner aktuellen Abfrage könnte man ohne Probleme ausbrechen und sich bspw. als Admin...
Hallo,

also den Code, den du da gebastelt hast, solltest du so auf keinen Fall mehr verwenden.
Warum nutzt du überhaupt mysqli? Das ist schon lange nicht mehr der Stand der Zeit.

Erstmal würde ich dir empfehlen, dich in PDO (PHP Data Objects) einzuarbeiten. Damit ist dein Code, deine Datenbankabfragen, von Haus aus sicherer, vorausgesetzt du nutzt Prepared Statements - was du unbedingt tun solltest, insbesondere bei Daten die vom Nutzer kommen.

Schau dir dazu gerne mal den Link hier an, dort wird das recht gut erklärt: https://www.php-einfach.de/mysql-tutorial/crashkurs-pdo/

Generell gilt: Traue niemals Daten, die vom Benutzer kommen.

Aus deiner aktuellen Abfrage könnte man ohne Probleme ausbrechen und sich bspw. als Admin der Seite anmelden, ohne das Passwort können zu müssen. Dafür reicht es schon als Benutzername ' OR 1=1 -- einzugeben.

Dazu kommt, dass du hier scheinbar das Passwort in Klartext verwendest und demnach auch speicherst? Ebenfalls sehr schlechte Idee. Bei der Registration solltest du das Passwort verschlüsseln. Dann holst du dir beim Login die User-Daten nur mittels Usernamen (nicht Passwort) und vergleichst dann die Passwörter.

Das könnte z.B so aussehen:

PHP:
// PDO-Verbindung zur Datenbank aufbauen
$pdo = new PDO("mysql:host=localhost;dbname=test", "user", "pass", [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);

$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';

// Wir suchen den Nutzer, mittels Prepared Statements (kein Ausbruch möglich), und nur anhand des Namens
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username");
$stmt->execute(['username' => $username]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);

// Hier prüfen wir, ob der Login valide ist, durch password_verify.
if ($user && password_verify($password, $user['password'])) {
    echo "Willkommen, " . htmlspecialchars($user['username']) . "!";
} 
else {
    echo "Benutzername oder Passwort falsch.";
}

Um Passwörter verschlüsselt und sicher zu speichern, kannst du sowas bei der Registration nutzen:
PHP:
// Wir hashen das Passwort, bevor wir es speichern
$password = password_hash($_POST['password'], PASSWORD_DEFAULT);

// Eintrag in die Datenbank, mittels prepared Statements und PDO.
$stmt = $pdo->prepare("INSERT INTO users (username, password) VALUES (:username, :password)");
$stmt->execute([
    'username' => $_POST['username'],
    'password' => $password
]);

Infos zur password_hash und password_verify-Methode findest du z.B in der Dokumentation:
 
Gemäß den aktuellen Sicherheitsstandards ist der Ansatz, den du verwendest, problematisch. Dein Code ist anfällig für SQL-Injection, eine der häufigsten und gefährlichsten Sicherheitslücken bei Webanwendungen. Das direkte Einfügen von Benutzereingaben in SQL-Abfragen ohne vorherige Validierung oder Säuberung der Daten ist nicht empfohlen.

Um die Sicherheit deines Login-Formulars zu erhöhen, solltest du vorbereitete Anweisungen (Prepared Statements) verwenden. Diese Technik wird von den meisten Datenbank-APIs unterstützt, einschließlich MySQLi. Sie sorgt dafür, dass Benutzereingaben von der Datenbank als Daten und nicht als Code interpretiert werden.

Hier ist ein Beispiel, wie du deinen Code mit MySQLi vorbereiteten Anweisungen sicherer gestalten kannst:

PHP:
$stmt = $conn->prepare("SELECT * FROM users WHERE username = ? AND password = ?");

$stmt->bind_param("ss", $username, $password);

$stmt->execute();

$result = $stmt->get_result();

Ein weiterer wichtiger Punkt ist die sichere Speicherung von Passwörtern. Es ist nicht empfehlenswert, Passwörter im Klartext in der Datenbank zu speichern. Stattdessen solltest du die PHP-Funktion `password_hash()` verwenden, um Passwörter zu hashen, bevor sie in die Datenbank gespeichert werden. Beim Überprüfen des Passworts nutzt du dann `password_verify()`.

Zusammenfassend solltest du:
- SQL-Injection durch prepared statements vermeiden.
- Passwörter hashen, bevor du sie speicherst.
- Die Funktionen `password_hash()` und `password_verify()` für Passwortmanagement verwenden.

Diese Maßnahmen erhöhen die Sicherheit deines Login-Formulars erheblich. Es mag ein bisschen mehr Arbeit erfordern, aber es ist entscheidend, um die Daten deiner Nutzer zu schützen.
 
Das sieht auf den ersten Blick gefährlich aus, vor allem wegen der potentiellen SQL-Injection-Gefahr. Wenn der Benutzername oder das Passwort irgendwelche bösartigen SQL-Befehle enthält, könnte das zu ernsthaften Sicherheitsproblemen führen. Ein klassisches Beispiel wäre, wenn jemand als Passwort `"' OR '1'='1"` eingibt. Dein Query würde dann tatsächlich alle Benutzer zurückgeben, weil die Bedingung immer wahr ist.

Um das zu vermeiden, solltest du auf jeden Fall Prepared Statements verwenden. Diese ermöglichen es, die Eingabedaten von der SQL-Abfrage zu trennen, sodass sie nicht als Code ausgeführt werden können. In PHP könntest du das mit `mysqli` so angehen:

Code:
$stmt = $conn->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->bind_param("ss", $username, $password);
$stmt->execute();
$result = $stmt->get_result();

Ein weiterer Punkt ist die Passwortspeicherung. Es ist wichtig, Passwörter nicht im Klartext in der Datenbank zu speichern. Die Verwendung von `password_hash()` beim Speichern und `password_verify()` beim Überprüfen ist ein Muss. Das stellt sicher, dass selbst im Fall eines Datenlecks die Passwörter nicht einfach gelesen werden können.

Manchmal stelle ich mir vor, dass es wie bei Architektur ist: Man kann eine Brücke bauen, die oberflächlich funktioniert, aber ohne solide Fundamente kann sie bei der kleinsten Belastung einstürzen. In der Softwareentwicklung sind diese Fundamente eben Sicherheitspraktiken und bewährte Methoden.

Vielleicht klingt das jetzt ein bisschen übertrieben, aber meiner Meinung nach lohnt es sich, hier von Anfang an sauber zu arbeiten. Es ist ähnlich wie beim Erlernen von Algorithmen - man kann schnell anfangen, aber den tiefen Nutzen erkennt man erst, wenn man auf die Details achtet.
 
Ich weiß nicht, ob das hilft, aber ich erinnere mich an eine Phase, in der ich selbst versucht habe, alles ohne Frameworks zu machen. Es ist echt beeindruckend, dass du dich da ranwagst! Aber bei deinem Code habe ich ein bisschen Bauchschmerzen, was die Sicherheit angeht.

Das Problem ist, dass du SQL-Injection-Angriffen Tür und Tor öffnest. Ich hatte mal eine ähnliche Situation, in der ich dachte, es sei alles gut, bis ich merkte, dass jemand ganz einfach auf meine Daten zugreifen konnte. Das war ein ziemlicher Augenöffner.

Vielleicht könntest du dir überlegen, Prepared Statements zu verwenden. Die sind ein bisschen wie ein Sicherheitsnetz beim Jonglieren - sie fangen dich auf, wenn du mal einen Fehler machst. Und was die Passwörter angeht, wäre es echt wichtig, sie nicht im Klartext in der Datenbank zu speichern

Manchmal fühlt es sich an, als würde man im Dunkeln tappen, aber solche kleinen Schritte können wirklich einen Unterschied machen. Vielleicht ist das auch nur bei mir so gewesen, aber es war ein gutes Gefühl, zu wissen, dass ich meine Anwendung ein Stück sicherer gemacht habe.
 
Okay, das sieht nach nem klassischen Fall von SQL-Injection-Risiko aus. Die Art, wie du da die Eingaben direkt in die Query packst, ist ne Einladung für jemanden, der dir böses will. Du willst da unbedingt auf Prepared Statements umsteigen. Damit machst du die Eingaben sicherer, weil sie nicht mehr direkt im SQL-String landen, sondern als Parameter übergeben werden.

Hier mal ein Beispiel, wie du das mit mysqli machen kannst:

PHP:
$stmt = $conn->prepare("SELECT * FROM users WHERE username = ? AND password = ?");

$stmt->bind_param("ss", $username, $password);

$stmt->execute();

$result = $stmt->get_result();

Noch was: Passwörter nie im Klartext in der Datenbank speichern. Immer schön mit `password_hash()` hashen und später mit `password_verify()` prüfen. Das ist dann auch sicherer, falls mal jemand an deine Datenbank rankommt.
 
Zurück
Oben