Frage

Meine Webanwendung verwendet Sitzungen, um Informationen über den Benutzer zu speichern, sobald er sich angemeldet hat, und um diese Informationen zu verwalten, wenn sie von Seite zu Seite innerhalb der App reisen. In dieser speziellen Anwendung speichere ich die user_id, first_name und last_name von der Person.

Ich möchte eine Option "Keep Me angemeldet" anmelden, die zwei Wochen lang einen Cookie auf den Benutzer des Benutzers stellt.

Was ist der beste Ansatz dafür? Ich möchte ihre nicht aufbewahren user_id Im Cookie würde es einem Benutzer, wie dies so aussieht, dass es so ist, die Identität eines anderen Benutzers zu fälschen.

War es hilfreich?

Lösung

OK, lassen Sie mich dies unverblümt einsetzen: Wenn Sie Benutzerdaten oder etwas von Benutzerdaten in einen Cookie für diesen Zweck eingeben, machen Sie etwas falsch.

Dort. Ich sagte es. Jetzt können wir zur tatsächlichen Antwort übergehen.

Was ist los mit Hashing -Benutzerdaten, fragen Sie? Nun, es kommt auf die Belichtungsoberfläche und die Sicherheit durch Dunkelheit an.

Stellen Sie sich eine Sekunde vor, dass Sie ein Angreifer sind. Sie sehen ein kryptografisches Cookie-Set für die Remin-Me in Ihrer Sitzung. Es ist 32 Zeichen breit. Gee. Das kann ein MD5 sein ...

Stellen wir uns auch eine Sekunde vor, dass sie den Algorithmus kennen, den Sie verwendet haben. Zum Beispiel:

md5(salt+username+ip+salt)

Jetzt muss ein Angreifer nur brutal das "Salz" erzwingen (was nicht wirklich ein Salz, aber später mehr), und er kann jetzt alle gefälschten Token erzeugen, die er mit jedem Benutzernamen für seine IP -Adresse will! Aber Brute-Forcing ein Salz ist schwer, oder? Unbedingt. Aber der moderne GPUs sind äußerst gut darin. Und wenn Sie nicht ausreichend Zufälligkeit darin verwenden (machen Sie es groß genug), wird es schnell fallen und damit die Schlüssel zu Ihrem Schloss.

Kurz gesagt, das einzige, was Sie schützt, ist das Salz, was Sie nicht so sehr schützt, wie Sie denken.

Aber warte!

All das wurde darauf hingewiesen, dass der Angreifer den Algorithmus kennt! Wenn es geheim und verwirrend ist, dann sind Sie in Sicherheit, oder? FALSCH. Diese Denkweise hat einen Namen: Sicherheit durch Dunkelheit, was sollte NOCH NIE sich verlassen.

Der bessere Weg

Der bessere Weg ist, die Informationen eines Benutzers niemals den Server verlassen zu lassen, mit Ausnahme der ID.

Wenn sich der Benutzer anmeldet, generieren Sie ein großes (128 bis 256 Bit) zufälliger Token. Fügen Sie dies zu einer Datenbanktabelle hinzu, die das Token der BenutzerID ordnet, und senden Sie es dann an den Client im Cookie.

Was ist, wenn der Angreifer den zufälligen Token eines anderen Benutzers erraten?

Nun, lass uns hier etwas Mathe machen. Wir generieren ein 128 -Bit -Token. Das bedeutet, dass es:

possibilities = 2^128
possibilities = 3.4 * 10^38

Um zu zeigen, wie absurd groß diese Zahl ist, stellen wir uns jeden Server im Internet vor (sagen wir heute 50.000.000), um diese Zahl mit einer Rate von jeweils 1.000.000.000 pro Sekunde zu brüten. In Wirklichkeit würden Ihre Server unter einer solchen Ladung schmelzen, aber lassen Sie uns dies ausspielen.

guesses_per_second = servers * guesses
guesses_per_second = 50,000,000 * 1,000,000,000
guesses_per_second = 50,000,000,000,000,000

Also 50 Grundreden pro Sekunde. Das ist schnell! Recht?

time_to_guess = possibilities / guesses_per_second
time_to_guess = 3.4e38 / 50,000,000,000,000,000
time_to_guess = 6,800,000,000,000,000,000,000

Also 6,8 Sextillionen Sekunden ...

Versuchen wir, das auf freundlichere Zahlen zu bringen.

215,626,585,489,599 years

Oder noch besser:

47917 times the age of the universe

Ja, das ist das 47917 -fache des Alters des Universums ...

Grundsätzlich wird es nicht geknackt.

Also zusammenfassen:

Der bessere Ansatz, den ich empfehle, ist, den Keks mit drei Teilen zu speichern.

function onLogin($user) {
    $token = GenerateRandomToken(); // generate a token, should be 128 - 256 bit
    storeTokenForUser($user, $token);
    $cookie = $user . ':' . $token;
    $mac = hash_hmac('sha256', $cookie, SECRET_KEY);
    $cookie .= ':' . $mac;
    setcookie('rememberme', $cookie);
}

Dann validieren:

function rememberMe() {
    $cookie = isset($_COOKIE['rememberme']) ? $_COOKIE['rememberme'] : '';
    if ($cookie) {
        list ($user, $token, $mac) = explode(':', $cookie);
        if (!hash_equals(hash_hmac('sha256', $user . ':' . $token, SECRET_KEY), $mac)) {
            return false;
        }
        $usertoken = fetchTokenByUserName($user);
        if (hash_equals($usertoken, $token)) {
            logUserIn($user);
        }
    }
}

Hinweis: Verwenden Sie nicht das Token oder die Kombination von Benutzer und Token, um einen Datensatz in Ihrer Datenbank zu suchen. Achten Sie immer darauf, einen auf dem Benutzer basierenden Datensatz zu erhalten, und verwenden Sie eine Zeitvergleichsfunktion, um das abgerufene Token anschließend zu vergleichen. Mehr über Timing -Angriffe.

Jetzt ist es sehr wichtig, dass die SECRET_KEY ein kryptografisches Geheimnis sein (erzeugt von so etwas wie /dev/urandom und/oder aus einem Hochentropieeingang abgeleitet). Ebenfalls, GenerateRandomToken() muss eine starke zufällige Quelle sein (mt_rand() ist nicht annähernd stark genug. Verwenden Sie eine Bibliothek wie z. RandomLib oder random_compat, oder mcrypt_create_iv() mit DEV_URANDOM)...

Das hash_equals() ist zu verhindern Timing -Angriffe. Wenn Sie eine PHP -Version unter Verwendung von PHP 5.6 der Funktion verwenden hash_equals() wird nicht unterstützt. In diesem Fall können Sie ersetzen hash_equals() Mit der TimingsFecompare -Funktion:

/**
 * A timing safe equals comparison
 *
 * To prevent leaking length information, it is important
 * that user input is always used as the second parameter.
 *
 * @param string $safe The internal (safe) value to be checked
 * @param string $user The user submitted (unsafe) value
 *
 * @return boolean True if the two strings are identical.
 */
function timingSafeCompare($safe, $user) {
    if (function_exists('hash_equals')) {
        return hash_equals($safe, $user); // PHP 5.6
    }
    // Prevent issues if string length is 0
    $safe .= chr(0);
    $user .= chr(0);

    // mbstring.func_overload can make strlen() return invalid numbers
    // when operating on raw binary strings; force an 8bit charset here:
    if (function_exists('mb_strlen')) {
        $safeLen = mb_strlen($safe, '8bit');
        $userLen = mb_strlen($user, '8bit');
    } else {
        $safeLen = strlen($safe);
        $userLen = strlen($user);
    }

    // Set the result to the difference between the lengths
    $result = $safeLen - $userLen;

    // Note that we ALWAYS iterate over the user-supplied length
    // This is to prevent leaking length information
    for ($i = 0; $i < $userLen; $i++) {
        // Using % here is a trick to prevent notices
        // It's safe, since if the lengths are different
        // $result is already non-0
        $result |= (ord($safe[$i % $safeLen]) ^ ord($user[$i]));
    }

    // They are only identical strings if $result is exactly 0...
    return $result === 0;
}

Andere Tipps

Sicherheitsbescheid: Das Basieren des Keks von einem MD5 -Hash deterministischer Daten ist eine schlechte Idee. Es ist besser, ein zufälliges Token zu verwenden, das von einem CSPRNG abgeleitet ist. Sehen Die Antwort von Ircmaxell zu dieser Frage für einen sichereren Ansatz.

Normalerweise mache ich so etwas:

  1. Benutzer meldet sich mit 'Keep Me angemeldet in' an.
  2. Sitzung erstellen
  3. Erstellen Sie einen Cookie namens etwas, das enthält: MD5 (Salz+Benutzername+IP+Salz) und ein Cookie namens etwas mit ID, das ID enthält
  4. Speichern Sie Cookie in der Datenbank
  5. Benutzer macht Sachen und Blätter ----
  6. Der Benutzer kehrt zurück, prüfen Sie nach etwas Cookie, wenn es vorhanden ist, holen Sie sich den alten Hash aus der Datenbank für diesen Benutzer, überprüfen Sie den Inhalt von Cookie etwas mit dem Hash aus der Datenbank, das auch mit einem neu berechneten Hash (für die IP) Also: Cookiehash == DataBaseHash == MD5 (Salz+Benutzername+IP+Salz), wenn sie es tun, goto 2, wenn sie nicht 1 goto 1

Aus Kurs können Sie verschiedene Cookie -Namen usw. verwenden. Außerdem können Sie den Inhalt des Cookies ein wenig ändern. Stellen Sie einfach sicher, dass dies nicht einfach erstellt wird. Sie können beispielsweise auch einen user_Salt erstellen, wenn der Benutzer erstellt wird, und dies auch in das Cookie einfügen.

Sie können auch SHA1 anstelle von MD5 (oder so ziemlich jedem Algorithmus) verwenden

Einführung

Dein Titel "Halten Sie mich angemeldet" - der beste Ansatz Machen Sie es mir schwer zu wissen, wo ich anfangen soll, denn wenn Sie den besten Ansatz betrachten, müssten Sie Folgendes in Betracht ziehen:

  • Identifikation
  • Sicherheit

Kekse

Cookies sind anfällig, zwischen den gängigen Browser-Cookie-Diebstahl-Schwachstellen und dem seiten-seiten-Skriptangriff müssen wir akzeptieren, dass Kekse nicht sicher sind. Um die Sicherheit zu verbessern, müssen Sie dies beachten php setcookies hat zusätzliche Funktionen wie z.

bool setcookie (String $ name [, String $ value [, int $ expire = 0 [, String $ path [, String $ Domain [, bool $ sicher = false [, bool $ httponly = false]]]]]]]))

  • sicher (mithilfe der HTTPS -Verbindung)
  • httponly (Identitätsdiebstahl durch XSS -Angriff reduzieren)

Definitionen

  • Token (unvorhersehbare zufällige Zeichenfolge von n Länge zB /dev /urandom)
  • Referenz (unvorhersehbare zufällige Zeichenfolge von n Länge z. B. /dev /urandom)
  • Signatur (generieren Sie einen Schlüsselhash -Wert mit der HMAC -Methode)

Einfacher Ansatz

Eine einfache Lösung wäre:

  • Der Benutzer ist mit Erinnerung an mich angemeldet
  • Login Cookie mit Token & Signature ausgestellt
  • Wann kommt es zurück, wird die Unterschrift überprüft
  • Wenn die Signatur in Ordnung ist .. dann wird Benutzername & Token in der Datenbank nachgeschlagen
  • Wenn nicht gültig .. kehren Sie zur Anmeldeseite zurück
  • Wenn sich automatisch gültig anmelden

Die obige Fallstudie fasst alle auf dieser Seite angegebenen Beispiele zusammen, aber sie benachteiligten sich

  • Es gibt keine Möglichkeit zu wissen, ob die Kekse gestohlen wurden
  • Angreifer können auf sensible Vorgänge wie die Änderung des Kennworts oder die Daten wie persönliche und Backinformationen usw. zugreifen.
  • Der kompromittierte Keks wäre immer noch für die Keksdauerspanne gültig

Bessere Lösung

Eine bessere Lösung wäre

  • Der Benutzer ist angemeldet und denken Sie daran, dass ich ausgewählt wurde
  • Generieren Sie Token & Signature und speichern Sie im Cookie
  • Die Token sind zufällig und nur für eine einzelne Autentifizierung gültig
  • Das Token wird bei jedem Besuch auf der Website ersetzt
  • Wenn ein nicht belegter Benutzer die Site besucht, werden die Signatur, Token und Benutzername verifiziert
  • Denken Sie daran, dass ich einen begrenzten Zugriff haben sollte und keine Änderung des Kennworts, persönlichen Informationen usw. zulassen sollte.

Beispielcode

// Set privateKey
// This should be saved securely 
$key = 'fc4d57ed55a78de1a7b31e711866ef5a2848442349f52cd470008f6d30d47282';
$key = pack("H*", $key); // They key is used in binary form

// Am Using Memecahe as Sample Database
$db = new Memcache();
$db->addserver("127.0.0.1");

try {
    // Start Remember Me
    $rememberMe = new RememberMe($key);
    $rememberMe->setDB($db); // set example database

    // Check if remember me is present
    if ($data = $rememberMe->auth()) {
        printf("Returning User %s\n", $data['user']);

        // Limit Acces Level
        // Disable Change of password and private information etc

    } else {
        // Sample user
        $user = "baba";

        // Do normal login
        $rememberMe->remember($user);
        printf("New Account %s\n", $user);
    }
} catch (Exception $e) {
    printf("#Error  %s\n", $e->getMessage());
}

Klasse verwendet

class RememberMe {
    private $key = null;
    private $db;

    function __construct($privatekey) {
        $this->key = $privatekey;
    }

    public function setDB($db) {
        $this->db = $db;
    }

    public function auth() {

        // Check if remeber me cookie is present
        if (! isset($_COOKIE["auto"]) || empty($_COOKIE["auto"])) {
            return false;
        }

        // Decode cookie value
        if (! $cookie = @json_decode($_COOKIE["auto"], true)) {
            return false;
        }

        // Check all parameters
        if (! (isset($cookie['user']) || isset($cookie['token']) || isset($cookie['signature']))) {
            return false;
        }

        $var = $cookie['user'] . $cookie['token'];

        // Check Signature
        if (! $this->verify($var, $cookie['signature'])) {
            throw new Exception("Cokies has been tampared with");
        }

        // Check Database
        $info = $this->db->get($cookie['user']);
        if (! $info) {
            return false; // User must have deleted accout
        }

        // Check User Data
        if (! $info = json_decode($info, true)) {
            throw new Exception("User Data corrupted");
        }

        // Verify Token
        if ($info['token'] !== $cookie['token']) {
            throw new Exception("System Hijacked or User use another browser");
        }

        /**
         * Important
         * To make sure the cookie is always change
         * reset the Token information
         */

        $this->remember($info['user']);
        return $info;
    }

    public function remember($user) {
        $cookie = [
                "user" => $user,
                "token" => $this->getRand(64),
                "signature" => null
        ];
        $cookie['signature'] = $this->hash($cookie['user'] . $cookie['token']);
        $encoded = json_encode($cookie);

        // Add User to database
        $this->db->set($user, $encoded);

        /**
         * Set Cookies
         * In production enviroment Use
         * setcookie("auto", $encoded, time() + $expiration, "/~root/",
         * "example.com", 1, 1);
         */
        setcookie("auto", $encoded); // Sample
    }

    public function verify($data, $hash) {
        $rand = substr($hash, 0, 4);
        return $this->hash($data, $rand) === $hash;
    }

    private function hash($value, $rand = null) {
        $rand = $rand === null ? $this->getRand(4) : $rand;
        return $rand . bin2hex(hash_hmac('sha256', $value . $rand, $this->key, true));
    }

    private function getRand($length) {
        switch (true) {
            case function_exists("mcrypt_create_iv") :
                $r = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
                break;
            case function_exists("openssl_random_pseudo_bytes") :
                $r = openssl_random_pseudo_bytes($length);
                break;
            case is_readable('/dev/urandom') : // deceze
                $r = file_get_contents('/dev/urandom', false, null, 0, $length);
                break;
            default :
                $i = 0;
                $r = "";
                while($i ++ < $length) {
                    $r .= chr(mt_rand(0, 255));
                }
                break;
        }
        return substr(bin2hex($r), 0, $length);
    }
}

Tests in Firefox & Chrome

enter image description here

Vorteil

  • Bessere Sicherheit
  • Begrenzter Zugang für Angreifer
  • Wenn Cookie gestohlen wird, ist es nur gültig für einen einzelnen Zugang
  • Wenn Sie als nächstes den ursprünglichen Benutzer auf die Website zugreifen

Nachteil

  • Unterstützt keine persistente Verbindung über mehrere Browser (Mobile & Web)
  • Der Cookie kann immer noch gestohlen werden, da der Benutzer nach dem nächsten Anmeldung erst die Benachrichtigung erhält.

Schnelle Lösung

  • Einführung des Genehmigungssystems für jedes System, das eine anhaltende Verbindung haben muss
  • Verwenden Sie mehrere Cookies für die Authentifizierung

Mehrfacher Cookie -Ansatz

Wenn ein Angreifer im Begriff ist, Cookies zu stehlen, fokussieren Sie ihn nur auf einer bestimmten Website oder einer bestimmten Domain, z. Beispiel.com

Aber wirklich können Sie einen Benutzer aus 2 verschiedenen Domänen authentifizieren (Beispiel.com & fakeaddSite.com) und lassen Sie es wie "Werbung Cookie" aussehen

  • Benutzer angemeldet an Beispiel.com Mit Erinnerung an mich
  • Benutzername speichern, Token, Referenz in Cookie
  • Speichern Sie Benutzername, Token, Referenz in der Datenbank, z. Memcache
  • Senden fakeaddSite.com
  • fakeaddSite.com verwendet den Verweis, um Benutzer und Token aus der Datenbank abzurufen
  • fakeaddSite.com speichert die Unterschrift
  • Wenn ein Benutzer Signaturinformationen mit iframe von fakeaddSite.com zurückgibt
  • Kombinieren Sie es Daten und führen Sie die Validierung durch
  • ..... Sie kennen die verbleibenden

Einige Leute fragen sich vielleicht, wie Sie 2 verschiedene Cookies verwenden können. Nun, es ist möglich, stellen Sie sich vor example.com = localhost und fakeaddsite.com = 192.168.1.120. Wenn Sie die Kekse inspizieren, würde dies so aussehen

enter image description here

Aus dem Bild oben

  • Die derzeit besuchte Website ist Localhost
  • Es enthält auch Cookies, die von 192.168.1.120 festgelegt wurden

192.168.1.120

  • Akzeptiert nur definiert HTTP_REFERER
  • Akzeptiert nur die Verbindung von angegebenen REMOTE_ADDR
  • Kein JavaScript, kein Inhalt, aber es bestehe eher nichts als Informationen zu signieren und füge sie von Cookie hinzu oder abzurufen

Vorteil

  • 99% Prozent der Fälle haben Sie den Angreifer ausgetrickst
  • Sie können das Konto im ersten Versuch im Angreifer leicht sperren
  • Der Angriff kann schon vor dem nächsten Anmeldung wie die anderen Methoden verhindert werden

Nachteil

  • Mehrere Anforderung an Server nur für eine einzige Anmeldung

Verbesserung

  • Fertig verwenden Sie iframe Verwendung ajax

Es gibt zwei sehr interessante Artikel, die ich gefunden habe, als ich nach einer perfekten Lösung für das "Remal-Me" -problem suchte:

Ich stellte einen Winkel dieser Frage hier, Und die Antworten führen Sie zu allen Token-basierten Timing-Cookie-Links, die Sie benötigen.

Grundsätzlich speichern Sie die BenutzerID im Cookie nicht. Sie speichern ein einmaliges Token (riesiger String), mit dem der Benutzer seine alte Anmeldession aufnimmt. Um es dann wirklich sicher zu machen, fragen Sie nach einem Passwort für schwere Operationen (wie das Ändern des Passworts selbst).

Ich würde den von Stefan erwähnten Ansatz empfehlen (dh die Richtlinien in folgen Verbesserte anhaltende Login -Cookie Best Practice) und empfehlen Sie auch, dass Sie sicherstellen, dass Ihre Cookies sind Httponly Cookies Sie sind also nicht zugänglich für potenziell böswillige JavaScript.

Generieren Sie einen Hash, vielleicht nur mit einem Geheimnis, nur Sie kennen, und speichern Sie ihn dann in Ihrem DB, damit er dem Benutzer zugeordnet werden kann. Sollte ganz gut funktionieren.

Alter Thread, aber immer noch ein gültiges Anliegen. Ich bemerkte einige gute Antworten auf die Sicherheit und die Vermeidung der Verwendung von „Sicherheit durch Dunkelheit“, aber die tatsächlichen technischen Methoden waren in meinen Augen nicht ausreichend. Dinge, die ich sagen muss, bevor ich meine Methode beisteuere:

  • NOCH NIE Speichern Sie ein Passwort in klarem Text ... Immer!
  • NOCH NIE Speichern Sie das Hashed -Passwort eines Benutzers an mehr als einem Ort in Ihrer Datenbank. Ihr Server -Backend ist immer in der Lage, das Hashed -Kennwort aus der Benutzertabelle zu ziehen. Es ist nicht effizienter, redundante Daten anstelle zusätzlicher DB -Transaktionen zu speichern, das Inverse ist wahr.
  • Ihre Sitzungs -ID sollten eindeutig sein, daher konnten keine zwei Benutzer konnten je Teilen Sie eine ID, daher der Zweck einer ID (könnte Ihre Führerschein-ID-Nummer jemals mit anderen Personen übereinstimmen? Nein.) Dies erzeugt eine zweiteilige eindeutige Kombination, die auf 2 eindeutigen Zeichenfolgen basiert. Ihre Sitzungstabelle sollte die ID als PK verwenden. Verwenden Sie eine andere Tabelle für vertrauenswürdige Geräte, die die Liste aller validierten Geräte enthält (siehe mein Beispiel unten) und unter Verwendung des Benutzernamens die Liste aller validierten Geräte enthält.
  • Es dient keinen Zweck, Daten bekannte Daten in ein Cookie zu erledigen, der Cookie kann kopiert werden. Was wir suchen, ist ein angemessenes Benutzergerät, um authentische Informationen bereitzustellen, die nicht ohne Angreifer erhalten werden können, der die Maschine des Benutzers beeinträchtigt (erneut siehe mein Beispiel). Dies würde jedoch bedeuten, dass ein legitimer Benutzer, der die statischen Informationen seiner Maschine verbietet (dh MAC -Adresse, Geräte -Hostname, Benutzeragent, wenn er durch Browser usw. eingeschränkt ist), davon zu verhindern Verwenden Sie diese Funktion. Wenn dies jedoch ein Problem ist, berücksichtigen Sie die Tatsache, dass Sie Benutzern, die sich einzigartig identifizieren, Wenn sie sich also weigern, ihren Mac zu fälschen, ihre Benutzeragent zu fälschen, ihren Hostnamen zu fälschen, ihren Hostnamen zu ändern, sich hinter Proxies zu verstecken usw., dann sind sie nicht identifizierbar und sollten niemals für einen automatischen Dienst authentifiziert werden. Wenn Sie dies wünschen, müssen Sie sich mit einer Client-Side-Software mit Smart-Card-Zugriff befassen, die die Identität für das verwendete Gerät festlegt.

Alles in allem gibt es zwei großartige Möglichkeiten, um Ihr System automatisch zu unterscheiden.

Erstens der billige, einfache Weg, der alles auf jemand anderen bringt. Wenn Sie Ihre Site -Unterstützung bei der Anmeldung bei beispielsweise Ihrem Google+ -Konto unterstützen, haben Sie wahrscheinlich eine optimierte Google+ -Taste, die den Benutzer angemeldet wird, wenn sie bereits bei Google angemeldet sind (ich habe das hier getan, um diese Frage zu beantworten, da ich immer bin in Google signiert). Wenn Sie möchten, dass der Benutzer automatisch angemeldet wird, wenn er bereits mit einem vertrauenswürdigen und unterstützten Authentikator angemeldet ist, und das Feld dazu überprüft, lassen Stellen Sie einfach sicher, dass der Server eine eindeutige ID in einer automatischen Signiertabelle speichert, die den Benutzernamen, die Sitzungs-ID und den Authenticator für den Benutzer verwendet. Da diese Anmeldemethoden AJAX verwenden, warten Sie trotzdem auf eine Antwort, und diese Antwort ist entweder eine validierte Antwort oder eine Ablehnung. Wenn Sie eine validierte Antwort erhalten, verwenden Sie sie als normal und laden Sie den protokollierten Benutzer wie gewohnt weiter. Andernfalls ist die Anmeldung fehlgeschlagen, aber sagen Sie es dem Benutzer nicht, einfach nicht angemeldet, er wird es bemerken. Dies soll verhindern, dass ein Angreifer, der Cookies gestohlen hat (oder sie gefälscht hat, um die Berechtigung zu eskalieren), zu erfahren, dass der Benutzer automatisch in die Website unterschreibt.

Dies ist billig und kann auch von einigen als schmutzig angesehen werden, weil es versucht, Ihre potenziell bereits in sich selbst unterschriebenen Orten wie Google und Facebook zu validieren, ohne es Ihnen zu sagen. Es sollte jedoch nicht bei Benutzern verwendet werden, die nicht gebeten haben, Ihre Website automatisch zu unterschreiben, und diese spezielle Methode dient nur für die externe Authentifizierung, wie bei Google+ oder FB.

Da ein externer Authentikator verwendet wurde, um den Server hinter den Kulissen zu informieren, ob ein Benutzer validiert wurde oder nicht, kann ein Angreifer nichts anderes als eine eindeutige ID erhalten, die für sich genommen nutzlos ist. Ich werde näher erläutern:

  • Benutzer 'Joe' besucht die Site zum ersten Mal, Sitzungs -ID in Cookie 'Session'.
  • Der Benutzer 'Joe' meldet sich an, eskaliert die Berechtigungen, erhält eine neue Sitzungs -ID und erneuert Cookie 'Session'.
  • Der Benutzer 'Joe' wählt mit Google+für automatischsignin und erhält eine eindeutige ID in Cookie 'KeepMesignedin'.
  • Benutzer 'joe' lässt Google sie angemeldet, sodass Ihre Website den Benutzer automatisch unterschreibt, wenn Sie Google in Ihrem Backend verwenden.
  • Angreifer versucht systematisch eindeutige IDs für 'keepMesignedIn' (dies ist öffentlich bekannt für jeden Benutzer) und wird nirgendwo anders angemeldet. Versucht einzigartige ID an 'Joe'.
  • Der Server erhält eine eindeutige ID für 'Joe', Pulls Match in DB für ein Google+ -Konto.
  • Server sendet Angreifer an eine Anmeldeseite, auf der eine AJAX -Anforderung an Google ausführt, um sich anzumelden.
  • Google Server empfängt die Anforderung und verwendet seine API, um anzuzeigen, dass Angreifer derzeit nicht angemeldet sind.
  • Google sendet die Antwort, dass derzeit keine Signal für diese Verbindung vorhanden ist.
  • Die Seite des Angreifers empfängt eine Antwort, das Skript leitet automatisch auf die Seite mit einem in der URL codierten Postwert weiter.
  • Die Anmeldeseite erhält den Postwert, sendet das Cookie für 'KeepMesignedIn' zu einem leeren Wert und einem gültigen bis zum Datum von 1-1-1970, um einen automatischen Versuch zu verhindern, was dazu führt, dass der Browser des Angreifers einfach das Cookie löscht.
  • Der Angreifer erhält eine normale Anmeldeseite zum ersten Mal.

Egal was, selbst wenn ein Angreifer eine ID verwendet, die nicht existiert, sollte der Versuch bei allen Versuchen scheitern, außer wenn eine validierte Antwort empfangen wird.

Diese Methode kann und sollte in Verbindung mit Ihrem internen Authentikator für diejenigen verwendet werden, die sich mit einem externen Authentikator für Ihre Website anmelden.

=========

Für Ihr eigenes Authentikatorsystem, mit dem Benutzer automatisch unterschrieben werden können, mache ich es so:

DB hat ein paar Tische:

TABLE users:
UID - auto increment, PK
username - varchar(255), unique, indexed, NOT NULL
password_hash - varchar(255), NOT NULL
...

Beachten Sie, dass der Benutzername in der Lage ist, 255 Zeichen lang zu sein. Ich habe mein Serverprogramm, das Benutzernamen in meinem System begrenzt, auf 32 Zeichen, aber externe Authentikatoren haben möglicherweise Benutzernamen mit ihrer @domain.

TABLE sessions:
session_id - varchar(?), PK
session_token - varchar(?), NOT NULL
session_data - MediumText, NOT NULL

Beachten Sie, dass in dieser Tabelle kein Benutzerfeld vorhanden ist, da sich der Benutzername, wenn er angemeldet ist, in den Sitzungsdaten befindet und das Programm keine Nulldaten zulässt. Session_ID und Session_Token können mit zufälligen MD5 -Hashes, SHA1/128/256 -Hashes, DateTime -Briefmarken mit zufälligen Zeichenfolgen generiert werden Mindern Sie die Brute-Force-Angriffe aus dem Boden, und alle von Ihrer Sitzungsklasse generierten Hashes sollten auf Übereinstimmungen in der Sitzungstabelle überprüft werden, bevor Sie versuchen, sie hinzuzufügen.

TABLE autologin:
UID - auto increment, PK
username - varchar(255), NOT NULL, allow duplicates
hostname - varchar(255), NOT NULL, allow duplicates
mac_address - char(23), NOT NULL, unique
token - varchar(?), NOT NULL, allow duplicates
expires - datetime code

MAC -Adressen sollten von Natur aus einzigartig sein, daher ist es sinnvoll, dass jeder Eintrag einen einzigartigen Wert hat. Hostnamen dagegen könnten legitim in separaten Netzwerken dupliziert werden. Wie viele Leute verwenden "Home-PC" als einen ihrer Computernamen? Der Benutzername stammt aus den Sitzungsdaten des Server -Backends, so dass es unmöglich ist, ihn zu bearbeiten. Was das Token betrifft, so sollte dieselbe Methode zum Generieren von Sitzungstoken für Seiten verwendet werden, um Token in Cookies für das Auto-Signin des Benutzers zu generieren. Schließlich wird der DateTime -Code hinzugefügt, wenn der Benutzer seine Anmeldeinformationen neu renovieren müsste. Aktualisieren Sie diese DATETIME -Zeit über die Nutzeranmeldung innerhalb weniger Tage oder zwingen Sie es, es zu verfallen, unabhängig vom letzten Anmeldung, der es nur für einen Monat beibehält, was auch immer Ihr Design vorschreibt.

Dies verhindert, dass jemand den Mac und den Hostnamen systematisch für einen Benutzer fälscht, in dem sie automatisch unterschrieben werden. NOCH NIE Lassen Sie den Benutzer ein Cookie mit seinem Passwort, dem Text löschen oder auf andere Weise aufbewahren. Lassen Sie das Token auf jeder Seitennavigation generiert werden, wie Sie es beim Sitzungs -Token tun würden. Dies reduziert die Wahrscheinlichkeit, dass ein Angreifer ein gültiges Token -Cookie erhalten und sie zum Login verwenden könnte. Einige Leute werden versuchen zu sagen, dass ein Angreifer die Kekse vom Opfer stehlen und einen Sitzungsangriff durchführen könnte, um sich anzumelden. Wenn ein Angreifer die Cookies stehlen könnte (was möglich ist), hätten er sicherlich das gesamte Gerät beeinträchtigt, was bedeutet, dass er das Gerät trotzdem verwenden könnte, was den Zweck des kompletten Diebstahls von Cookies zunimmt. Solange Ihre Website über HTTPS (was sie beim Umgang mit Kennwörtern, CC -Nummern oder anderen Anmeldesystemen) läuft, haben Sie dem Benutzer, den Sie in einem Browser können, den Schutz gewährt.

Eine Sache, die Sie beachten sollten: Sitzungsdaten sollten nicht ablaufen, wenn Sie Auto-Signin verwenden. Sie können die Fähigkeit ablehnen, die Sitzung fälschlicherweise fortzusetzen, aber die Validierung in das System sollte die Sitzungsdaten wieder aufnehmen, wenn es anhaltende Daten sind, die erwartet werden, dass sie zwischen den Sitzungen fortgesetzt werden. Wenn Sie sowohl persistente als auch nicht-persistente Sitzungsdaten möchten, verwenden Sie eine andere Tabelle für persistente Sitzungsdaten mit dem Benutzernamen als PK und lassen Sie den Server sie so abrufen, wie es die normalen Sitzungsdaten wäre, verwenden Sie einfach eine andere Variable.

Sobald auf diese Weise eine Anmeldung erreicht wurde, sollte der Server die Sitzung weiterhin validieren. Hier können Sie die Erwartungen an gestohlene oder kompromittierte Systeme codieren. Muster und andere erwartete Ergebnisse von Anmeldungen zu Sitzungsdaten können häufig zu Schlussfolgerungen führen, dass ein System entführt oder Cookies geschmiedet wurden, um Zugriff zu erhalten. Hier kann Ihre ISS-Technologie Regeln einstellen, die eine Kontosperrung oder eine automatische Aufnahme eines Benutzers aus dem Auto-Signin-System auslösen und Angreifer lange genug heraushalten, damit der Benutzer feststellt, wie der Angreifer erfolgreich war und wie er abschneiden soll.

Stellen Sie sicher, dass sich jeder Wiederherstellungsversuch, Kennwort- oder Anmeldungsfehler über den Schwellenwert verändert, dass ein automatisches Signal deaktiviert wird, bis der Benutzer ordnungsgemäß validiert und dies bestätigt.

Ich entschuldige mich, wenn jemand erwartet hatte, dass Code in meiner Antwort ausgegeben wird, das wird hier nicht passieren. Ich werde sagen, dass ich PHP, JQuery und Ajax verwende, um meine Websites auszuführen, und Windows nie als Server benutze ... jemals.

Meine Lösung ist so. Es ist nicht 100% kugelsicher, aber ich denke, es wird Sie für die meisten Fälle sparen.

Wenn der Benutzer mit diesen Informationen erfolgreich eine Zeichenfolge erstellen:

$data = (SALT + ":" + hash(User Agent) + ":" + username 
                     + ":" + LoginTimestamp + ":"+ SALT)

Verschlüsseln $data, setzen Sie den Typ auf Httponly und setze Cookie.

Wenn der Benutzer zu Ihrer Website zurückkehrt, machen Sie folgende Schritte:

  1. Holen Sie sich Cookie -Daten. Entfernen Sie gefährliche Charaktere im Keks. Explodieren Sie es mit : Charakter.
  2. Überprüfen Sie die Gültigkeit. Wenn Cookie älter als x Tage ist, dann leiten Sie die Benutzer auf die Anmeldeseite um.
  3. Wenn Cookie nicht alt ist; Holen Sie sich die neueste Kennwortänderungszeit aus der Datenbank. Wenn das Kennwort nach dem letzten Login -Benutzer des Benutzers geändert wird, um die Anmeldeseite zu leiten.
  4. Wenn der Pass kürzlich nicht geändert wurde; Holen Sie sich den aktuellen Browser -Agenten des Benutzers. Überprüfen Sie, ob (CurrentUseragentHash == CookieUseragentHash). Wenn Agenten gleich sind, gehen Sie zu dem nächsten Schritt, sonst leiten Sie sich auf die Anmeldeseite aus.
  5. Wenn alle Schritte erfolgreich den Benutzernamen genehmigen.

Wenn sich die Benutzer anmeldet, entfernen Sie diesen Cookie. Erstellen Sie einen neuen Cookie, wenn der Benutzer neu-Logine ist.

Ich verstehe das Konzept, verschlüsselte Sachen in einem Cookie zu speichern, wenn es sich um die verschlüsselte Version handelt, die Sie zum Hacken benötigen. Wenn mir etwas fehlt, kommentieren Sie bitte.

Ich denke darüber nach, diesen Ansatz zu verfolgen, um mich an mich zu erinnern. Wenn Sie Probleme sehen können, kommentieren Sie bitte.

  1. Erstellen Sie eine Tabelle zum Speichern von "Meme Me" -Daten in - getrennt in die Benutzertabelle, damit ich mich von mehreren Geräten anmelden kann.

  2. Bei erfolgreichem Login (mit Erinnerung an mich tickte):

    a) Generieren Sie eine eindeutige zufällige Zeichenfolge, die als BenutzerID auf dieser Maschine verwendet werden soll: BigUerID

    b) Erzeugen Sie eine eindeutige zufällige Zeichenfolge: Bigey

    c) Lagern Sie einen Keks: BigUerid: Bigey

    d) In der Tabelle "Erinnere dich an mich", fügen Sie einen Datensatz mit: Userid, IP -Adresse, BigUerid, Bigey hinzu

  3. Wenn Sie versuchen, auf etwas zuzugreifen, das Anmeldung erfordert:

    a) Überprüfen Sie nach dem Cookie und suchen Sie nach BigUserid & Bigey mit einer passenden IP -Adresse nach

    b) Wenn Sie es finden, protokollieren Sie die Person in die Benutzer -Tabelle "Soft Login", so dass Sie für gefährliche Operationen eine vollständige Anmeldung auffordern können.

  4. Markieren Sie beim Abmelden alle "Remember Me" -Datensätze für diesen Benutzer als abgelaufen.

Die einzigen Schwachstellen, die ich sehen kann, ist;

  • Sie könnten den Laptop eines Menschen erhalten und seine IP -Adresse mit dem Cookie fälschen.
  • Sie könnten jedes Mal eine andere IP -Adresse fälschen und das Ganze erraten - aber mit zwei großen String, die übereinstimmen, wäre das ... eine ähnliche Berechnung wie oben ... Ich habe keine Ahnung ... große Chancen?

Ich las alle Antworten und fand es immer noch schwierig, das zu extrahieren, was ich tun sollte. Wenn ein Bild 1K -Wörter wert ist, hoffe ich, dass dies anderen hilft Verbesserte anhaltende Login -Cookie Best Practice

enter image description here

Wenn Sie Fragen, Feedback oder Vorschläge haben, werde ich versuchen, das Diagramm zu aktualisieren, um den Neuling nachzudenken, der versucht, eine sichere anhaltende Anmeldung zu implementieren.

Durch die Implementierung einer Funktion "Keep Me Me Meed in" müssen Sie genau definieren, was dies für den Benutzer bedeutet. Im einfachsten Fall würde ich das verwenden, um zu bedeuten, dass die Sitzung eine viel längere Auszeit hat: 2 Tage (z. B.) anstelle von 2 Stunden. Dazu benötigen Sie Ihren eigenen Sitzungsspeicher, wahrscheinlich in einer Datenbank, damit Sie benutzerdefinierte Ablaufzeiten für die Sitzungsdaten festlegen können. Dann müssen Sie sicherstellen, dass Sie einen Keks einstellen, der ein paar Tage (oder länger) anhält, anstatt zu verfallen, wenn sie den Browser schließen.

Ich kann dich fragen hören: "Warum 2 Tage? Warum nicht 2 Wochen?". Dies liegt daran, dass die Verwendung einer Sitzung in PHP die Ablauf automatisch zurückschiebt. Dies liegt daran, dass die Ablauf einer Sitzung in PHP tatsächlich eine müßige Auszeit ist.

Nachdem ich das gesagt habe, würde ich wahrscheinlich einen härteren Zeitüberschreitungswert implementieren, den ich in der Sitzung selbst speichere, und in 2 Wochen oder so herausgegeben und Code hinzufügen, um das zu sehen und die Sitzung gewaltsam ungültig zu machen. Oder zumindest um sie auszumelden. Dies bedeutet, dass der Benutzer gebeten wird, sich regelmäßig anzumelden. Yahoo! macht dies.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top