Подтвердить что ты не робот

Система входа в систему PHP: Запомнить меня (постоянный файл cookie)

Я хочу добавить флажок "запомнить меня" перед входом в систему.

Каков наилучший способ безопасного хранения файла cookie в браузере пользователя?

Например, Facebook имеет свой флажок "помнить меня", чтобы каждый раз, когда вы вводили facebook.com, вы уже вошли в систему.

Мой текущий логин использует простые сеансы.

4b9b3361

Ответ 1

Этот вопрос задается очень часто, вот некоторые ссылки для вас.

В ответе на этот вопрос собраны также некоторые большие ресурсы: Окончательное руководство по аутентификации веб-сайта

Ответ 2

Обновление (2017-08-13). Чтобы понять, почему мы разделяем selector и token, вместо того, чтобы просто использовать token, прочитайте в этой статье о разделении токенов для предотвращения атак синхронизации в SELECT-запросах.

Я собираюсь извлечь стратегию, изложенную в этом сообщении в блоге об обеспечении долгосрочной долгосрочной аутентификации, поскольку это охватывает много нас интересует только " запомнить меня.

Преамбула - Структура базы данных

Нам нужна отдельная таблица из таблицы наших пользователей, которая выглядит так (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`)
);

Важно то, что selector и token являются отдельными полями.

После входа в систему

Если у вас нет random_bytes(), просто возьмите копию 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)
        ]
    );
}

Повторная аутентификация при загрузке страницы

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
    }
}

Подробнее

Мы используем 9 байтов случайных данных (base64, закодированных до 12 символов) для нашего селектора. Это обеспечивает 72 бита пространства ключей и, следовательно, 2 36 бит сопротивления столкновению (атаки на день рождения), который больше, чем наша емкость (integer(11) UNSIGNED), в 16 раз.

Мы используем 33 байта (264 бит) случайности для нашего фактического аутентификатора. Это должно быть непредсказуемым во всех практических сценариях.

Мы храним SHA256 хэш аутентификатора в базе данных. Это уменьшает риск олицетворения пользователя после утечки информации.

Мы пересчитываем хэш SHA256 значения аутентификатора, хранящегося в cookie пользователя, затем сравниваем его с сохраненным хэшем SHA256, используя hash_equals() для предотвращения временных атак.

Мы отделили селектор от аутентификатора, потому что поиск БД не является постоянным. Это устраняет потенциальное влияние временных утечек на поиск, не вызывая резкого падения производительности.