Idee für zusätzliches Sicherheitsmerkmal beim Login

  • Hallo,

    da ich viel mit Login-Systemen zu tun hab hab ich mir mal ein System überlegt, dass XSS absolut wirkungslos machen könnte (zumindest was das Fishen von loginrelevanten Cookies angeht):

    Grundstruktur davon sieht so aus:

    login.php

    • Prüfen von Benutzernamen und Passwort (natürlich salted)
    • Setze eine Session für den Benutzer wie gehabt ( mit session_set_cookie_params() Cookie auf HTTP only setzen)
    • Speichere eine uniqid() in die Benutzertabelle, des gerade eingeloggten Benutzers
    • Lege einen Cookie mit ebendieser Uniqid an -> HTTP only

    index.php

    • Prüfe User-ID mittels Session
    • Lies die Datenbank-Tabelle aus und hole Uniqid() aus Datenbank
    • Prüfe, ob Uniqid aus Tabelle mit Cookie übereinstimmt
      • Wenn nein: Logout -> Zerstöre alle Sessiondaten, lösche Uniqid Cookie
      • Wenn ja: Zeige Seite im eingeloggtem Zustand (HIER KÖNNTE XSS nun stattfinden)

    Seitenende von index.php

    • Generiere neue Uniqid() und ersetze den aktuellen Eintrag in der Tabelle
    • Öffne eine AJAX Verbindung und lass so einen neuen Cookie mit der neuen Uniqid() (aus der Datenbank) generieren
    • Eventuell: neue Session mit regenerate_session_id() erzeugen.

    Das war nur mal so ein provisorischer Gedankengang, wie man XSS wirkungslos machen könnte:
    Dadurch, dass für den Login auch die Uniqid() benötigt wird und diese (auch wenn man es schafft den Cookie auszulesen, während die Seite aufgebaut wird, mit XSS) am Ende der Seite wieder geändert wird, ist die Seite wirkungslos noch bevor der XSS Angreifer was mit der Uniqid() anfangen kann.

    Das Problem ist hier leider mit setcookie gegeben: setcookie darf ja nicht nach einer Ausgabe kommen und die Ausgabe mit ob_start zu puffern wäre unsinnig, weil das Cookie dann erst recht wieder den aktuellen Inhalt hat und XSS nach der Ausgabe zuschlagen kann - auch den Cookie per JS zu setzen widerspricht natürlich allen Sicherheitsanforderungen - einzige Idee wäre dies mit Ajax zu lösen - Unschön halt, dass JavaScript und Cookies für diese Methode zwingend erforderlich ist...

    Das ist nur mal so ein Gedankengang wie sowas funktionieren könnte - wenn jemand eine schönere Idee für die Cookiesache am Seitenende weiß, bitte :)

    Lg
    Matze

    PHP
    if(isset($this) || !isset($this)){ // that's the question...

    2 Mal editiert, zuletzt von Teron Gerofied (17. November 2011 um 15:05)

  • Eine einfachere Variante wäre wohl auch noch:

    login.php

    • Prüfen von Benutzernamen und Passwort (salted Password)
    • Setze Session -> Session-Cookie: HTTP Only
    • Speichere aktuellen Timestamp in $ts
    • Schreibe $uid = uniqid() in Datenbank: user_session_salt
    • Schreibe md5($ts . $uid) in Datenbank: user_session_uniqid
    • Schreibe Cookie mit inhalt $ts (Cookie-Name: "data")

    index.php

    • Prüfe Session und hole Benutzerdaten
    • Prüfe ob: md5( $_COOKIE['data'] . user_session_salt ) == user_session_uniqid
      • Wenn nein: Sessions zerstören, alles löschen
      • Wenn ja: Dann setze neue neuen Timestamp in Cookie und generiere neue user_session_uniqid mit diesem Timestamp
        • Zeige Seite im eingeloggten Zustand

    logout.php

    • Zerstöre Session
    • Lösche Salt und Code aus DB

    Ich glaub diese Routine ist sinnvoller, da das Problem mit setcookie gelöst ist und XSS trotzdem sinnlos ist, da man ohne den Salt, der nur beim Loginmechanismus generiert wird auch mit dem Cookie nicht weiter kommt, zumindest wenn der Benutzer nicht eingeloggt ist... - und wenn er eingeloggt ist wird sowieso bei jedem Seitenaufruf ein neuner TS generiert

    EDIT:
    Man könnte am Seitenende Javascript den aktuellsten TS ($ts_new) der PHP Datei übergeben, JS einen neuen Cookie setzen lassen, und am Ende der PHP Datei den Timestamp so in die Datenbank schreiben - das würde (dank der Tatsache, dass JS alles nach der Reihe abarbeitet) verhindern, dass man per XSS den neuen Timestamp auslesen kann, sofern nach dem letzten Javascript keine GET oder POST ausgegeben werden - dann hat man aber wieder das Problem, dass HTTP only im Weg steht - ist die Frage, was sicherer ist...

    EDIT 2:
    Ok, ein Timestamp wäre eig idiotisch, denn wenn man die Sessid "gehijacked" hat muss man nur mehr auf gut Glück alle Timestamps durchrennen - Uniqid würde in dem Fall auch salt ersparen

    PHP
    if(isset($this) || !isset($this)){ // that's the question...

    5 Mal editiert, zuletzt von Teron Gerofied (17. November 2011 um 16:41)