Система входа PHP:Запомни меня (постоянный файл cookie) [дубликат]
-
01-10-2019 - |
Вопрос
На этот вопрос уже есть ответ здесь:
- «Держать меня в системе» — лучший подход 12 ответов
Я хотел бы добавить флажок «Запомнить меня» перед входом в систему.
Как лучше всего безопасно хранить файлы 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()
для предотвращения атак по времени.
Мы отделили селектор от аутентификатора, поскольку поиск в БД не осуществляется в постоянном времени.Это устраняет потенциальное влияние утечек времени на поиск, не вызывая при этом резкого снижения производительности.