Прежде чем войти в систему, я хочу добавить флажок «запомнить меня».
Каков наилучший способ безопасного хранения файла cookie в браузере пользователя?
Например, у Facebook есть флажок «запомнить меня», чтобы каждый раз, когда вы вводили facebook.com, вы уже вошли в систему.
Мой текущий логин использует простые сеансы.
Этот вопрос задают много, вот некоторые ссылки для вас.
Кроме того, в ответе на этот вопрос собраны некоторые большие ресурсы: окончательное руководство по аутентификации веб-сайта
Обновление (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('Ymd\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()
для предотвращения временных атак.
Мы отделили селектор от аутентификатора, потому что поиск БД не является постоянным. Это устраняет потенциальное влияние временных утечек на поиск, не вызывая резкого падения производительности.