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

StackOverflow https://stackoverflow.com/questions/3128985

Вопрос

На этот вопрос уже есть ответ здесь:

Я хотел бы добавить флажок «Запомнить меня» перед входом в систему.

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

Например, в Facebook есть флажок «Запомнить меня», поэтому каждый раз, когда вы заходите на facebook.com, вы уже авторизуетесь.

Мой текущий вход в систему использует простые сеансы.

Это было полезно?

Решение

Другие советы

Обновление (13 августа 2017 г.):Чтобы понять, почему мы расстаемся 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(), просто возьмите копию случайный_компат.

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 байт случайных данных (12 символов в кодировке Base64).Это обеспечивает 72 бита пространства ключей и, следовательно, 236 бит устойчивости к коллизиям (атаки дня рождения), что больше, чем емкость нашей памяти (integer(11) UNSIGNED) в 16 раз.

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top