Как спроектировать REST-вход без сохранения состояния с двухфакторной аутентификацией (2FA)?
Я борюсь с концепцией разработки API RESTful-аутентификации без сохранения состояния с многофакторной аутентификацией.
Почти по определению, потребность в 2FA требует нескольких состояний; войдите в систему с именем пользователя / паролем, затем отправьте "код" (TOTP, SMS-код, ответ на вопрос о проверке и т. д.). Это также подразумевает конечный автомат (FSM) некоторого вида.
Насколько я могу судить, единственные варианты, которые существуют для поддержания механизма без сохранения состояния:
- клиент должен передавать некоторую информацию о состоянии (например, текущее состояние FSM) при отправке данных для перехода в следующее состояние,
- состояние должно сохраняться на стороне сервера,
- клиент должен передавать ВСЕ данные при каждом запросе, что позволило ему достичь текущего состояния
Очевидно, что передача ВСЕХ данных бессмысленна. Таким образом, это подразумевает либо передачу информации о состоянии (непрозрачной или иной) в запросе, либо сохранение состояния на сервере.
Или есть какая-то другая техника, которую мне не хватает?
1 ответ
Я добавляю решение, которое придумал, на случай, если оно будет выгодным для кого-то еще в будущем. Обратите внимание, что в этом случае PVQ расшифровывается как "Персональный вопрос проверки" (т.е. аутентификация на основе знаний).
В конце я разработал конечную точку входа в систему так, чтобы она требовала:
- Заголовок авторизации (который является токеном 2FA):
Authorization: authType=”PVQ” token=”<tokenid>”
- имя пользователя
- пароль
Если Authorization
заголовок отсутствует, конечная точка возвращает 401 и устанавливает WWW-Authenticate
заголовок, указывающий, что для входа требуется токен 2FA (т. е. заголовок авторизации). параметр может быть PVQ, SMS, TOTP и т. д. (в зависимости от конфигурации пользователя)
WWW-Authenticate : authType="PVQ"
Если клиент получает ответ 401/WWW-Authenticate, он обязан вызвать конечные точки 2FA:
вызов / получить (получить жетон вызова)
- Клиент: отправляет имя пользователя / пароль
- Сервер: отвечает с идентификатором, и либо
- вопрос (PVQ),
- или просто отправляет отправляет СМС код через стороннего СМС провайдера
проверить / получить (получить токен 2FA, необходимый для
Authorization
заголовок)- Клиент: отправляет
- ID, полученный в
challenge/get
- имя пользователя Пароль
- ответ на вызов (т. е. текстовый ответ на PVQ, или код SMS, или код TOTP)
- ID, полученный в
- Сервер: возвращает
- 2FA значение токена
- Клиент: отправляет
Теперь клиент может вызвать конечную точку входа в систему с требуемым: имя пользователя / пароль / токен аутентификации.
В конце концов, не существует "состояния", скажем, что клиент возвращается на сервер, но компромисс для этого заключается в том, что комбинация имени пользователя и пароля должна отправляться на каждый запрос для подсистемы 2FA.
На стороне сервера в БД хранится некоторая информация о состоянии в контексте кода SMS или вопроса PVQ, отправленного пользователю, а также эфемерный токен 2FA аутентификации (одноразовое использование и фиксированный TTL).