Как правильно организовать регистрацию и авторизацию пользователей сайта (Java)?

Доброго времени суток!
В процессе создания сайта возникла потребность в регистрации / авторизации пользователей.

Используемые технологии:
  • Для серверной части использую Java, в частности Servlet'ы.
  • Данные пользователей и прочие изменяемые данные хранятся в PostgreSQL.
  • Для доступа к PostgreSQL из java использую (jdbc:postgresql).
  • В качестве контейнера для Servlet'ов использую Tomcat.
  • Перед Tomcat'ом стоит nginx для отдачи статики. (css / js / html / img)
  • Для передачи данных между браузером и сервером, без обновления страницы, использую AJAX (&& json).
Требуемый сценарий:
  1. Пользователь попадает на страницу регистрации, создает учетную запись. Данные отправляются на сервер и сохраняются в БД. Пароль, предварительно, солится и хэшируется. (Алгоритм хэширования и порядок добавления соли еще не выбрал, это не основной вопрос, но буду рад авторитетному мнению, разбирающихся людей)
  2. После регистрации, при обращениях к определенным страницам (сервлетам), пользователь проходит процедуру авторизации. Вводит логин / пароль. Логин и пароль отправляются на сервер в post запросе. Там от пароля вычисляется хэш и сравнивается с тем что в базе. Если хэши совпадают, пользователь признается авторизованным и получает что-то, что впоследствии он будет предъявлять, при доступе к страницам, требующим авторизацию. Это что-то так же заносится в базу.
  3. И собственно сам доступ к страницам требующим авторизацию. Пользователь отправляет, это "что-то", полученное при регистрации и в ответ получает страницу. (По сути, это будет результат работы сервлета (данные), которые на стороне браузера с помощью js превращаются в страницу).
Вопрос 1. Верно ли я понял процесс Регистрации и Авторизации пользователей?
Вопрос 2. "Что-то" выдаваемое при авторизации, называют "токеном". Что представляет собой токен? (случайную строку, которая является по сути идентификатором? Если да - то какой она должна быть длины, нужно ли ее шифровать и где хранить на стороне клиента?)
Вопрос 3. Слышал про OAuth и долго и коротко живущие токены (refresh token и access token). Как я понял основная концепция в ограничении времени доступа злоумышленника при краже токенов. Такая схема представляется более надежной, но опять же возникают те же вопросы и даже новые. Что такое токен, какая длина токена считается безопасной, нужно ли его шифровать и как его генерировать. А так же где и как хранить на стороне браузера.
В некоторых статьях предлагается при обновлении любого из токенов, присылать новую пару токенов (вместо одного, обновляемого), в связи с этим возникает вопрос, как решается ситуация, когда Пользователь запросил обновление refresh token и в этот момент потерял связь (не смог получить новую пару). После восстановления связи пользователь пытается запросить обновление токенов еще раз (используя старый refresh token). Однако на сервере уже хранится новый refresh token, тот самый что не дошел до пользователя. И все что остается пользователю это повторная авторизация (логин / пароль). Стоит ли переживать в реальной жизни из-за такой ситуации? или это допустимое и очень редкое затруднение, которое не будет заставлять пользователей постоянно, снова и снова вводить свой пароль?
Вопрос 4. Достаточен ли уровень безопасности OAuth или стоит искать что-то другое? jwt?
  • Вопрос задан
  • 10944 просмотра
Решения вопроса 1
AlexXYZ
@AlexXYZ
O Keep Clear O
В основном всё верно. Я бы немного подправил следующие моменты:
>> Пользователь отправляет, это "что-то", полученное при регистрации и в ответ получает страницу
Не пользователь, а клиент (пользователь сидит за компом). Но клиент - не ваша программа, а в основном браузер (curl - тоже клиент) и ваша программа максимум может иметь доступ к некоторым кукам, да и то не ко всем (как настроит куку сервер, см. cookie httponly). Сервер проверяет токен и сопоставляет контекст приложения (php/java) с параметрами пользователя (_GET/_POST/_SESSION), поэтому код backend как правило никак не может влиять на контекст пользователя, только если в нём нет ошибок на выполнение критичных операций. (Естественно, что нужно разбираться в архитектуре сервера, т.к. на уровне фильтров, а в tomcat/IIS они есть, можно сделать много чего нехорошего ещё до обработки запроса под пользователем).

>> Что представляет из себя токен? (случайную строку, которая является по сути идентификатором? Если да - то какой она должна быть длины, нужно ли ее шифровать и где хранить на стороне клиента?
Токен - это уникальный идентификатор сессии в формате именно строки. Можно в него вставить JSON.stringify(), но браузер всё равно будет идентифицировать его как строку. Символы ему без разницы. Выдаётся на сессию на одном клиенте. Т.е. если вы подключитесь/логинитесь разными браузерами под одним логином пользователя, то у них будут разные токены. Однако, если вы технически сможете своровать токен из одного браузера и воткнуть его в другой, то фактически будете работать под одной сессией в разных браузерах и проходить аутентификацию во втором браузере не придётся (Иногда этим можно пользоваться для тестов). Именно по этом причине токены надо зарывать по максимуму, т.е. отправлять их в заголовках и в протоколе HTTPS. Только это не касается протокола Kerberos, там аутентификация производится другим механизмом и завладевание кукой не даст результата (весьма сложный механизм, используется в корпоративных сетях, не в интернете).
где хранить на стороне клиента - Для кук браузер сам их хранит и сам же дописывает в заголовки при выполнении запросов, так что это делается прозрачно. Поставьте fiddler, там всё видно.
нужно ли ее шифровать - Обычно нет.

>> Слышал про OAuth и долго и коротко живущие токены
OAuth используется, когда вы хотите привлечь большое количество пользователей, предполагая, что у них есть аккаунты в соцсетях, т.е. этот протокол упрощает и регистрацию и аутентификацию, но сложнее в настройках, чем form-based. тут есть одна тонкость - аккаунт пользователя в вашей программе надо будет всё равно создавать и связывать его с аккаунтом профиля в соцсети (сейчас подробнее не скажу, давно занимался)
Теперь какая связь между токеном и OAuth - Делаем выход из контекста рассуждения "на уровень выше" и вспоминаем, что OAuth - протокол аутентификации, а после аутентификации нужно (барабанная дробь ...) тадам - установить токен сессии!!! Т.е. с помощью OAuth вы только проверяете валидность пользователя, затем ваша программа выясняет с каким аккаунтом на вашем сайте он связан и устанавливает токен/куку, чтобы не проходить аутентификацию каждого запроса от пользователя аккаунтов с соцсети. Ну, представьте, что даже на CSS и IMG надо будет требовать подтверждение? (если только не настроен NGINX для отдачи статики, как вы указали выше).

>> Если да - то какой она должна быть длины
Посмотрите на форматы и размеры токенов, которые выдают соцсети? Да, взять этот же toster.ru, вот прям сейчас:

719fc6c4999547af95b58b252dd5255d.png

Токен сессии придумываете самостоятельно. Хоть sid. Формат строки токена ничем не определён. Главное, чтобы при идентификации пользователя случайно не выдать аналогичный токен другому пользователю, а то получится, что два пользователя идентифицируются сервером как один, кто первый залогинился. Так что одна из проблем сервера - обеспечить уникальность токенов сессий, а это важный раздел безопасности. Вполне можно поискать способы компрометации выдачи "нужных" токенов и тогда безопасность сайта под большой угрозой.

>> Достаточен ли уровень безопасности OAuth или стоит искать что то другое? jwt?
Поскольку OAuth тоже начинается с "вешалки", т.е. с form-based аутентификации в соцсети, то главное обеспечить достаточный уровень секретности - HTTPS и всё будет норм.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
angrySCV
@angrySCV
machine learning, programming, startuping
1. Верно (но это подходы из 90х)
2. зачем шифровать случайную строку? шифруют данные, токен может как иметь какие-то данные (которые тогда обязательно шифруются), либо не иметь никаких данных, тогда шифровать не надо, и такие "токены" обычно в виде сессий передаются пользователям.
3. шифрованные токены, обычно содержать в себе все что необходимо, смысл в том чтоб ты после получения токена расшифровывал его и получал все необходимые данные для авторизации из самого токена, а не искал что-то в базе.
браузер может сохранять данные через кукисы, а также в локалСторейдж (ну есть еще экзотические варианты)
4. немного сумбурно, и перепутанно, OAuth - всего лишь определяет набор правил по которому осуществляется безопасная авторизация, jwt - формат передачи данных, шифрованный json (можно применять как разные форматы при передаче данных, так и разные правила при авторизации).
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы