System logowania PHP: Remember Me (persistent cookie) [duplikat]

To pytanie ma już odpowiedź tutaj:

Chciałbym dodać opcję" Zapamiętaj mnie " przed zalogowaniem.

Jaki jest najlepszy sposób bezpiecznego przechowywania plików cookie w przeglądarce użytkownika?

Na przykład Facebook ma swoje pole wyboru "Zapamiętaj mnie", dzięki czemu za każdym razem, gdy wchodzisz facebook.com jesteś już zalogowany.

Moje obecne logowanie używa prostych sesji.

Author: Scott Arciszewski, 2010-06-28

2 answers

To pytanie jest często zadawane, oto kilka linków dla Ciebie.

Istnieje również kilka wielkich zasobów zebranych razem w odpowiedzi na to pytanie: The Definitive Guide To website Authentication

 34
Author: Paul Dixon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:23

Update (2017-08-13) : aby zrozumieć, dlaczego oddzielamy selector i token, zamiast używać token, przeczytaj Ten artykuł o dzieleniu tokenów, aby zapobiec atakom timingowym w zapytaniach SELECT.

Zamierzam wyodrębnić strategię opisaną w tym poście na blogu o bezpiecznym uwierzytelnianiu długoterminowym , ponieważ obejmuje to wiele obszarów i interesuje nas tylko część "Zapamiętaj mnie".

Preambuła - Struktura Bazy Danych

Chcemy oddzielnej tabeli od tabeli naszych użytkowników, która wygląda tak (MySQL):

CREATE TABLE `auth_tokens` (
    `id` integer(11) not null UNSIGNED AUTO_INCREMENT,
    `selector` char(12),
    `token` char(64),
    `userid` integer(11) not null UNSIGNED,
    `expires` datetime,
    PRIMARY KEY (`id`)
);

Najważniejsze jest to, że selector i token są oddzielnymi polami.

Po Zalogowaniu

Jeśli nie masz random_bytes(), po prostu pobierz kopię random_compat.

if ($login->success && $login->rememberMe) { // However you implement it
    $selector = base64_encode(random_bytes(9));
    $authenticator = random_bytes(33);

    setcookie(
        'remember',
         $selector.':'.base64_encode($authenticator),
         time() + 864000,
         '/',
         'yourdomain.com',
         true, // TLS-only
         true  // http-only
    );

    $database->exec(
        "INSERT INTO auth_tokens (selector, token, userid, expires) VALUES (?, ?, ?, ?)", 
        [
            $selector,
            hash('sha256', $authenticator),
            $login->userId,
            date('Y-m-d\TH:i:s', time() + 864000)
        ]
    );
}

Ponowne Uwierzytelnianie Przy Ładowaniu Strony

if (empty($_SESSION['userid']) && !empty($_COOKIE['remember'])) {
    list($selector, $authenticator) = explode(':', $_COOKIE['remember']);

    $row = $database->selectRow(
        "SELECT * FROM auth_tokens WHERE selector = ?",
        [
            $selector
        ]
    );

    if (hash_equals($row['token'], hash('sha256', base64_decode($authenticator)))) {
        $_SESSION['userid'] = $row['userid'];
        // Then regenerate login token as above
    }
}

Szczegóły

Używamy 9 bajtów losowych danych (base64 zakodowane do 12 znaków) dla naszego selektora. To zapewnia 72 bity przestrzeni kluczy i dlatego 236 bity odporności na kolizje( birthday attacks), która jest większa niż nasza pojemność pamięci (integer(11) UNSIGNED) o współczynnik 16.

Używamy 33 bajtów (264 bity) losowości dla naszego rzeczywistego authenticatora. Powinno to być nieprzewidywalne we wszystkich praktycznych scenariuszach.

Przechowujemy hash SHA256 authenticatora w bazie danych. Zmniejsza to ryzyko podszywania się pod użytkowników po wyciekach informacji.

Obliczamy ponownie Skrót SHA256 wartości authenticator przechowywanej w pliku cookie użytkownika porównuje go z zapisanym skrótem SHA256 przy użyciu hash_equals() aby zapobiec atakom czasowym.

Oddzieliliśmy selektor od authenticatora, ponieważ wyszukiwanie DB nie jest stałe. Eliminuje to potencjalny wpływ wycieków czasu na wyszukiwanie bez powodowania drastycznego spadku wydajności.

 36
Author: Scott Arciszewski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-13 20:30:38