Здравствуйте. Делаю регистрацию на свой сайт и столкнулся со следующими вопросами, которые просто не дают мне покоя.
1. Насколько грамотно, правильно и безопасно хранить данные пользователя в следующем виде?
Есть у меня одна кука "UD". В ней информация о пользователе хранится в следующем виде: 191c90e0e6ad59a59588b23fb896ef0b-000014
Здесь набор символов до "-" - это шифр пароля (нет-нет, он не один (шифр), пароль, лежащий в самой БД до этого тоже был очень сильно зашифрован), а цифры после "-" - id пользователя. Также есть сомнения по-поводу того, что если эту куку "угонят", то смогут получить доступ к аккаунту этого пользователя. Другое дело, что любую куку угнать можно.
2. Как избежать перенагрузки на БД при следующем подходе?
Каждый раз, когда загружается любая страница моего сайта, мне нужно отобразить в шапке (да и не только, например) имя и фамилию пользователя, а также его аватар, путь к которому хранится в БД. Но ведь я так сервер положу? Только представьте, что будет, если (знаю, эта сумма для меня недостижима, это просто для примера) 100'000 пользователей одновременно откроют по 10 страниц каждый. С другой стороны, такой подход дает возможность постоянно "следить" за статусом пользователя, забанен он или нет. Я не знаю, может быть есть какой-то способ, позволяющий избежать такого? Просто мне кажется просто убийственным каждый раз при загрузке посылать запрос в БД, узнающий по обрезанному из куки ID имя, фамилию, статус аккаунта и аватар аккаунта пользователя.
У кого какие советы есть по этому поводу? Может быть я зря парюсь, может быть сервера намного более выносливы, чем я думаю?
1. Допустим, мы хотим держать пользователя залогиненным долгое время (месяц или больше). Что у нас меняется на одном и том же устройстве? Только IP.
Привяжите в генерацию HASH-ключа hash(logonName+UserAgent+password).
Логику используйте https://ru.wikipedia.org/wiki/CRAM-MD5
2. Храните основные данные пользователя в сессии (сохранить сразу после авторизации).
При выполнении важных операций делайте проверку на бан из базы данных.
Дмитрий Энтелис: Я не думаю, что они медленны настолько, что я успею заварить чай, пока они будут подгружаться ;) А за микросекундами я не гонюсь. Имхо, если вам делает погоду несолько микро-(пусть мили-)секунд, то у меня для Вас плохие новости :)
Спасибо большое за ответ. Действительно, что-то я забыл совсем про сессии.
Но ведь при закрытии браузера сессия накроется, насколько мне известно. А мне она нужна ровно настолько, насколько зашел пользователь, например, на 2 недели. Как мне тогда перезугружать данные сессии ТОЛЬКО тогда, когда пользователь заново открыл браузер, чтобы все равно не выполнять заполнении данных сессии каждый раз при загрузке страницы?
eucalipt: после того, как куки будут проверены переменные сессии автоматически возвратит Вам сервер (т.к. там уже все будет лежать готовое).
Далее - сами решайте: обновлять Вам их при каждом входе пользователя или брать старые (из текущей сессии).
xmoonlight: Вы меня не так поняли, наверно. Сейчас попробую пояснить.
Вот есть у меня кука с моими данными, ей осталось жить, например, 14 дней, потому что пользователь только что вошел (и в момент входа сгенерировались еще и переменные сессии). Так вот. Пришло время отобразить имя и фамилию пользователя в шапке сайта, я лезу за переменными, хранящимися в сессии, все норм, отобразилось. А теперь пользователь закрыл браузер (сессия удалилась), но не вышел из аккаунта. Теперь снова вошел в браузер, пришли время отобразить его имя и фамилию, НО, упс, нужных данных нет, потому что они были стерты. Вывод, их надо генерировать только тогда, когда их нет.
Получается, что каждый раз нужно просто выполнять проверку if (isset($_SESSION["firstName"]) && isset($_SESSION["lastName"])) {}?
В принципе, ресурсов потратится меньше, чем если к БД обращаться. Да и по сравнению с обращанием к БД, должно быстрее выйти, имхо.
eucalipt: браузер то закрыли, а куки браузера - остались и сессия на сервере - тоже хранится. Вы открыли снова браузер, обновили(перевыписали) токен на нужный ID сессии и сервер Вам отдаст переменные из серверной сессии (из хранилища сессий).
Что if нужен - это обязательно. Еще не плохо бы права при обновлении токена проверить тоже)
xmoonlight: не сочтите за наглость, но не могли бы вы в коде с комментариями объяснить? Хотя бы какую-то часть. Я не понял вот это: "обновили (перевыписали) токен на нужный ID сессии и сервер Вам отдаст переменные из серверной сессии (из хранилища сессий)." Как я узнаю, какой нужный ID сессии? Немного не догоняю.
eucalipt: куки в браузере: SESSID, HASH. перевыписать: значит послать команду серверу на обновление HASH-a на эту сессию (SESSID). Если hash неверен, то сервер в ответ пришлет, что hash устарел и попросит клиент (браузер) переавторизоваться заново. HASH привязан к SESSID на сервере.
Хотите сделать прально - вначале пишите АЛГОРИТМ! и НИКАКОГО КОДА!
Тут явно кто то не понимает как работает сессия.
PHP если видит сессионную куку идет в хранилище сессий, берет там ВСЕ данные этой сессии и кладет их в переменную $_SESSION.
По умолчанию данные сессии хранятся в файлах что является АДСКИ медленным.
Да, можно переключиться на хранение сессий например в redis - но по сути добавляется еще 1 элемент в системе просто так, не говоря уже о том, что механизм сессий это некое неявное поведение.
Гораздо проще и для мелкого проекта правильнее не использовать сессии вообще, делая ровно 1 запрос в базу. Это отлично работает, гарантирую.
Дмитрий Энтелис: по-умолчанию сессия хранится в кэше инстанса процесса php. ничего не нужно выдумывать.... "Тут явно кто то не понимает как работает сессия" )
Дмитрий Энтелис: 1 запрос в базу? То есть вы хотите сказать, что быстрее при каждой загрузке страницы брать из базы имя пользователя, статус его бана, его права, статус подтвержденности аккаунта, чем использовать такое?
<?php
if (isset($_SESSION['username'])) {
// то берем из сесси
} else {
// то подключаемся к бд, берем оттуда, и потом уже все равно пилим в сессию, чтобы в следующий раз из сессии брало, а не в базу лезло. Пусть лезет в базу, только когда сессии нет.
}
?>
По-моему мой вариант правильнее, что ли. Только вот что касается авторизации пользователя, сюда уже да, лучше сессии не сунуть, пусть только на куках держится. Хотя, это тоже спорный вопрос. Насчет безопасности использования сессий, однако, тут еще холивары не устраивались.
Матвей Мамонов: "Насчет безопасности использования сессий" - вот давайте в этой ветке не будем, что есть 2 вида кук и переменные сессии и главное не заблудиться в них и т.д., иначе ща опять растянется)
xmoonlight: Нет, я на самом деле думаю, что сессии - это хорошая практика, если их грамотно использовать и не злоупотреблять этим.
Я вот, например, недавно сидел, ломал голову, как сделать, своего рода, оповещение? Такой выплывающий сверху блок в пастельном красном, оповещающий пользователя о том, что он что-то забыл/упустил. Так вот, думал я, думал, как сделать так, чтобы пользователю это сообщение не надоедало (не выплывало при каждом открытии новой страницы), но и не забывал он о нем. Так вот, как я считаю, лучшим решением тут будет использовать сессии. Один раз показал, установил переменную сессии - и все, и забыл. Больше пользователь это назойливое сообщение не увидит. Перезашел в браузер - снова увидил.
Куда лучше, чем показывать при каждом входе в аккаунт(!) (слишком редко) или чем при каждом открытии новой страницы (слишком часто).
Короче говоря, если использовать сессии грамотно, то от них будет толк, я считаю. Немаловажно ими не злоупотреблять.
А вопрос по поводу того, использовать их, чтобы отслеживать, авторизировался пользователь, или нет, для меня до сих пор остается открытый.
По крайней мере, если речь идет о безопасности, то просто сунуть туда то, что "не жалко". Например, тот же логин пользователя, или статус напоминания - показано уже, или еще нет.
Матвей Мамонов: HTML5 Storage еще забыли упомянуть для управления оповещениями (чтобы автоматом убрать в параллельных окнах браузера и запоминать промежуточные состояния).... *и нафиг я это сказал*)))
Я что, зря выдумывал такую схему что ли? Ахаха, вот уж что правда, век живи, век учись. А я как обычно узнаю о всех новинках только тогда, когда это уже не новинки. И да ладно бы, если бы просто не новинки, так это уже устаревшим считается, когда я об этом узнаю. Что ж, спасибо за наводку так или иначе ;)
То есть вы хотите сказать, что быстрее при каждой загрузке страницы брать из базы имя пользователя, статус его бана, его права, статус подтвержденности аккаунта, чем использовать такое
я тут немножечко проснулся - а как вы вообще хотите хранить такие вещи как статус бана и права в сессии? допустим модератор забанил пользователя. а у пользователя в сессии то по прежнему закешировано что все ок.
Дмитрий Энтелис: ну в общем-то да, для этого так или иначе каждый раз к БД подключаться нужно, Вы правы, что-то я не подумал об этом. Но для остальных-то можно использовать такую схему. Имя пользователя, его права (они не будут часто меняться, а чуть что - перезайдет, и все нормально будет), статус подтвержденности аккаунта - все это подходит под мою схему.
Матвей Мамонов: тут важно на что именно BAN. Если на сайт - то да. Если на операции - то тут можно проверять BAN только перед операцией, тем самым экономя ресурс БД.
xmoonlight: тоже верно. Смысла банить на сайт нет вообще. Ибо пользователь может просто выйти из аккаунта и начать просмотр как гость. А что, мне, мол, закрыли, а гостю всегда открыто. Так что бан в любом случае только на операции идти будет.
1. Норм. Для полного счастья можно генерить новую куку при каждой авторизации.
Что бы их не своровали - https
2. Не надо заниматься преждевременной оптимизацией.
Сотни тысяч пользователей Одновременно - это проект с сотнями серверов
Только осталось непонятным вот это: "Для полного счастья можно генерить новую куку при каждой авторизации.".
У меня эти "величины" постоянны для каждого пользователя. Сколько бы раз и с какого места и устройства я бы не заходил в свой аккаунт, эта кука у меня всегда будет выглядеть как шифр.пароля.из.бд-юзер.айди.