Integration

PHP-Session-Login

Schlanker Auth-Layer für statische PHP-Seiten: in-page Login-Form, bcrypt-Hashes in einer Datei, Session-Cookie. Funktioniert auch da, wo Basic Auth nicht durchkommt.

Live im Einsatz intern, hinter Login (Ein IT-Projekt mit KI) seit 24.05.2026
Implementierung der Zugangsschutz über PHP-Sitzungen + Apache .htaccess mit DirectoryIndex index.php
Hash-Verfahren bcrypt (PHP password_hash mit PASSWORD_DEFAULT, Cost 12)
Cookie KIR_SESSION · 30 Tage · Secure · HttpOnly · SameSite=Lax

Warum überhaupt?

Klassisches HTTP Basic Auth ist der einfachste Schutz für eine private Webseite – funktioniert aber in manchen Browser-/Proxy-Konstellationen schlicht nicht: der Anmelde-Dialog kommt nie hoch, der Besucher sieht nur eine leere Seite oder eine generische Fehlermeldung. Genau das war bei Voggenreiter mit dem ursprünglichen Apache-Basic-Auth-Setup auf intern, hinter Login passiert.

Die Antwort: ein eigener Auth-Layer in PHP. Statt sich auf den Browser- Dialog zu verlassen, liefert die Seite eine ganz normale HTML-Login- Karte aus – das funktioniert immer, egal welcher Browser oder welcher Proxy dazwischen sitzt. Gleichzeitig bleibt der Aufwand klein: eine einzelne PHP-Datei, keine Datenbank, keine externen Dienste.

So läuft eine Anfrage

Jede ausgelieferte Seite endet auf .php und beginnt mit einer einzigen Zeile: require_once $_SERVER['DOCUMENT_ROOT'] . '/der Zugangsschutz über PHP-Sitzungen';. Diese Datei prüft das Session-Flag $_SESSION['authed'].

Ist es gesetzt, kehrt sie still zurück und die Seite rendert normal. Ist es nicht gesetzt, antwortet sie selbst mit HTTP 401 und einer eingebetteten Login-Karte. Wer Benutzername und Passwort einträgt, schickt einen POST an dieselbe URL: der Zugangsschutz über PHP-Sitzungen prüft den Hash mit password_verify, regeneriert die Session-ID, setzt das Auth-Flag und macht einen 302-Redirect auf die ursprünglich angefragte Seite. Ab dann liefert der Browser den Cookie KIR_SESSION bei jedem Request mit – 30 Tage lang.

Was den Layer hart macht

  • bcrypt statt MD5/APR1: moderne Hashes mit Cost 12, kein selbstgebautes Passwort-Vergleichen
  • Session-Regeneration nach Login: session_regenerate_id(true) verhindert Session-Fixation
  • Cookie-Härtung: Secure (nur HTTPS), HttpOnly (kein JS-Zugriff), SameSite=Lax (kein CSRF aus Fremdseiten)
  • Brute-Force-Bremse: 500 ms usleep bei falschem Passwort macht systematisches Durchprobieren spürbar teurer
  • Source bleibt verborgen: der Zugangsschutz über PHP-Sitzungen liegt zwar im Web-Root, wird aber von Apache als PHP geparst – der Klartext-Hash wird nie ausgeliefert
  • Sichere Defaults für Security-Header: HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy und Permissions-Policy werden direkt in der Zugangsschutz über PHP-Sitzungen per header() gesetzt – wirkt auch dann, wenn Apache mod_headers mal nicht greift

Bewusste Trennung von der Plattform

Wer sich auf der Webseite anmeldet, ist kein Nutzer des darunter liegenden Systems (auf der NAS: kein DSM-User, kein SFTP-Konto, kein SMB-Zugriff). Die Hash-Liste in der Zugangsschutz über PHP-Sitzungen ist eine völlig eigene Welt. Selbst wenn das Web-Passwort kompromittiert würde, käme jemand maximal an die ohnehin private Webseite – nicht an Dateien, nicht an die DSM-Oberfläche, nicht an andere Dienste am gleichen Rechner.

Skalierungs-Pfad

Der Aufbau ist absichtlich klein gehalten: eine Datei, eine Liste. Für ein bis fünf Nutzer ist das ideal – kein Overhead, kein Server, keine Datenbank. Wenn mehr Nutzer dazukommen, lässt sich die User-Liste in eine SQLite-Datei auslagern oder gegen einen externen OIDC-Provider tauschen. Die eigentliche Auth-Mechanik (Cookie, Session-Handling, in-page-Form, Security-Header) bleibt dabei identisch.

Wofür sich PHP-Session-Login NICHT lohnt

  • Öffentliche Webseiten mit Self-Service-Registrierung – da fehlen Mail-Bestätigung, Passwort-Reset, Account-Sperre als eigenständige Subsysteme
  • Mehrstufige Rollen-/Rechtekonzepte – der Layer kennt nur eingeloggt oder nicht, kein RBAC
  • Hosts, die kein PHP ausliefern können (rein statische Hoster wie GitHub Pages) – dort hilft nur ein vorgeschalteter Reverse-Proxy mit eigener Auth

Eingesetzt in

← zurück zur Baustein-Übersicht